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

Fixed CORE-1898: Increase the password length from 8 characters, CORE-3372: Simplify process of non-default security database creation

This commit is contained in:
alexpeshkoff 2011-12-23 12:43:58 +00:00
parent c2e17f5cbf
commit 7fb8ebd3a9
86 changed files with 4210 additions and 837 deletions

View File

@ -178,35 +178,40 @@ stopSuperServerIfRunning() {
}
#------------------------------------------------------------------------
# Generate new sysdba password - this routine is used only in the
# rpm file not in the install script.
# Create new password string - this routine is used only in
# silent mode of the install script.
generateNewDBAPassword() {
createNewPassword() {
# openssl generates random data.
openssl </dev/null >/dev/null 2&>/dev/null
if [ $? -eq 0 ]
then
# We generate 20 random chars, strip any '/''s and get the first 8
NewPasswd=`openssl rand -base64 20 | tr -d '/' | cut -c1-8`
# We generate 40 random chars, strip any '/''s and get the first 20
NewPasswd=`openssl rand -base64 40 | tr -d '/' | cut -c1-20`
fi
# mkpasswd is a bit of a hassle, but check to see if it's there
if [ -z "$NewPasswd" ]
then
if [ -f /usr/bin/mkpasswd ]
then
NewPasswd=`/usr/bin/mkpasswd -l 8`
fi
fi
# If openssl is missing...
if [ -z "$NewPasswd" ]
then
NewPasswd=`dd if=/dev/urandom bs=10 count=1 2>/dev/null | od -x | head -n 1 | tr -d ' ' | cut -c8-27`
fi
# On some systems the mkpasswd program doesn't appear and on others
# there is another mkpasswd which does a different operation. So if
# On some systems even this routines may be missing. So if
# the specific one isn't available then keep the original password.
if [ -z "$NewPasswd" ]
then
NewPasswd="masterkey"
fi
echo "$NewPasswd"
}
#------------------------------------------------------------------------
# Generate new sysdba password - this routine is used only in
# silent mode of the install script.
generateNewDBAPassword() {
NewPasswd=`createNewPassword`
writeNewPassword $NewPasswd
}

View File

@ -40,16 +40,6 @@ if [ $RunUser = firebird ]; then
addFirebirdUser
fi
# Create the fbmgr shell script.
if [ -x @FB_SBINDIR@/fbmgr.bin ]; then
cat > @FB_SBINDIR@/fbmgr <<EOF
#!/bin/sh
FIREBIRD=@FB_CONFDIR@
export FIREBIRD
exec @FB_SBINDIR@/fbmgr.bin \$@
EOF
fi
# Update ownership and SUID bits for files.
fixFilePermissions
@ -65,11 +55,11 @@ buildUninstallFile
# Update the /etc/inetd.conf or xinetd entry
updateInetdServiceEntry
# Change sysdba password (use embedded access)
setDBAPassword
# Get inetd to reread new init files.
resetInetdServer
# start the db server so we can change the password
# start the RDBMS server
startService @FIREBIRD_ARCH_TYPE@
# Change sysdba password
changeDBAPassword

View File

@ -296,6 +296,17 @@ askForOrigDBAPassword() {
}
#------------------------------------------------------------------------
# Ask user to enter new DBA password string
# !! This routine is interactive !!
getNewDBAPasswordFromUser()
{
AskQuestion "Please enter new password for SYSDBA user: "
echo $Answer
}
#------------------------------------------------------------------------
# Modify DBA password to value, asked from user.
# $1 may be set to original DBA password
@ -313,8 +324,7 @@ askUserForNewDBAPassword() {
NewPasswd=""
while [ -z "$NewPasswd" ]
do
AskQuestion "Please enter new password for SYSDBA user: "
NewPasswd=$Answer
NewPasswd=`getNewDBAPasswordFromUser`
if [ ! -z "$NewPasswd" ]
then
if ! runSilent "@FB_BINDIR@/gsec -user sysdba -password $OrigPasswd -modify sysdba -pw $NewPasswd"
@ -437,6 +447,26 @@ changeDBAPassword() {
}
#------------------------------------------------------------------------
# Set sysdba password.
setDBAPassword() {
if [ -z "$InteractiveInstall" ]
then
passwd=`createNewPassword`
else
passwd=`getNewDBAPasswordFromUser`
fi
if [ ! -z "$passwd" ]
then
passwd=masterkey
fi
runSilent "@FB_BINDIR@/gsec -add sysdba -pw $passwd"
}
#------------------------------------------------------------------------
# buildUninstallFile
# This will work only for the .tar.gz install and it builds an

View File

@ -359,10 +359,11 @@ $(NBACKUP): $(NBACKUP_Objects) $(COMMON_LIB)
# plugins - some of them are required to build examples, use separate entry for them
#
.PHONY: udr legacy_user_management trace auth_debug
.PHONY: udr legacy_user_management trace auth_debug
makePluginName= $(PLUGINS)/$(LIB_PREFIX)$(1).$(SHRLIB_EXT)
UDR_PLUGIN = $(call makePluginName,udr_engine)
LEGACY_USER_MANAGER = $(call makePluginName,Legacy_UserManager)
SRP_USER_MANAGER = $(call makePluginName,Srp)
AUTH_DEBUGGER = $(call makePluginName,Auth_Debug)
BUILD_DEBUG:=
@ -370,7 +371,7 @@ ifeq ($(TARGET),Debug)
BUILD_DEBUG:=auth_debug
endif
plugins: udr legacy_user_management trace $(BUILD_DEBUG)
plugins: udr legacy_user_management srp_user_management trace $(BUILD_DEBUG)
udr: $(UDR_PLUGIN) $(PLUGINS)/udr_engine.conf
@ -395,6 +396,10 @@ auth_debug: $(AUTH_DEBUGGER)
$(AUTH_DEBUGGER): $(AUTH_DEBUGGER_Objects) $(COMMON_LIB)
$(LINK_PLUGIN) $(call LIB_LINK_SONAME,$(notdir $@).0) -o $@ $^ $(LINK_PLUG_LIBS) $(FIREBIRD_LIBRARY_LINK)
srp_user_management: $(SRP_USER_MANAGER)
$(SRP_USER_MANAGER): $(SRP_USERS_MANAGE_Objects) $(COMMON_LIB)
$(LINK_PLUGIN) $(call LIB_LINK_SONAME,$(notdir $@).0) -o $@ $^ $(LINK_PLUG_LIBS) $(FIREBIRD_LIBRARY_LINK) $(MATHLIB)
#___________________________________________________________________________
# codes - developers change them sometimes

View File

@ -128,6 +128,9 @@ ATOMIC_OPTIONS=@ATOMIC_OPTIONS@
# needed at least for solaris inline assembly routines
CAS_OPTIONS=@CAS_OPTIONS@
# multiple-precision integer library
MATHLIB=@MATHLIB@
# Default programs and tools to be used in the build process
SH= sh -c
@ -307,7 +310,7 @@ LINK_TRACE_LIBS = -L$(LIB) $(SO_LINK_LIBS)
LINK_FIREBIRD = $(LIB_LINK) $(LINK_FIREBIRD_SYMBOLS) $(LIB_LINK_OPTIONS) $(LIB_FIREBIRD_OPTIONS) $(UNDEF_FLAGS)\
$(call LIB_LINK_SONAME,$(LibrarySoName)) $(call LIB_LINK_RPATH,lib)
LINK_FIREBIRD_LIBS = -L$(LIB) $(LIB_GUI) $(SO_LINK_LIBS)
LINK_FIREBIRD_LIBS = -L$(LIB) $(LIB_GUI) $(SO_LINK_LIBS) $(MATHLIB)
LINK_ENGINE = $(LIB_LINK) $(LINK_PLUGIN_SYMBOLS) $(LIB_LINK_OPTIONS) $(LIB_FIREBIRD_OPTIONS) $(UNDEF_FLAGS)\
$(call LIB_LINK_SONAME,$(EngineSoName)) $(call LIB_LINK_RPATH,lib)

View File

@ -49,10 +49,12 @@ AllObjects += $(YValve_Objects)
# Remote
Remote_Common:= $(call dirObjects,remote)
Remote_Server:= $(call dirObjects,remote/server) $(call makeObjects,auth/SecurityDatabase,LegacyServer.cpp)
# legacy security database LegacyServer.cpp should become SA plugin
Remote_Client:= $(call dirObjects,remote/client) $(call makeObjects,auth/SecurityDatabase,LegacyClient.cpp)
Remote_Common:= $(call dirObjects,remote) $(call dirObjects,auth/SecureRemotePassword)
Remote_Server:= $(call dirObjects,remote/server) $(call dirObjects,auth/SecureRemotePassword/server) \
$(call makeObjects,auth/SecurityDatabase,LegacyServer.cpp)
# legacy security database LegacyServer.cpp should become plugin soon
Remote_Client:= $(call dirObjects,remote/client) $(call dirObjects,auth/SecureRemotePassword/client) \
$(call makeObjects,auth/SecurityDatabase,LegacyClient.cpp)
Remote_Server_Objects:= $(Remote_Common) $(Remote_Server)
Remote_Client_Objects:= $(Remote_Common) $(Remote_Client)
@ -165,6 +167,13 @@ LEGACY_USERS_MANAGE_Objects:= $(call makeObjects,auth/SecurityDatabase,LegacyMan
AllObjects += $(LEGACY_USERS_MANAGE_Objects)
# SRP-based users management in security database
SRP_USERS_MANAGE_Objects:= $(call dirObjects,auth/SecureRemotePassword/manage) \
$(call dirObjects,auth/SecureRemotePassword)
AllObjects += $(SRP_USERS_MANAGE_Objects)
# Multihop authentication debugger
AUTH_DEBUGGER_Objects:= $(call makeObjects,auth,AuthDbg.cpp)

View File

@ -43,6 +43,18 @@ AC_ARG_WITH([$1],
AC_SUBST([$3])
])
define([XE_SAVE_ENV], [
pre_save_restore_cflags=$CFLAGS
pre_save_restore_cxxflags=$CXXFLAGS
pre_save_restore_libs=$LIBS
])
define([XE_RESTORE_ENV], [
CFLAGS=$pre_save_restore_cflags
CXXFLAGS=$pre_save_restore_cxxflags
LIBS=$pre_save_restore_libs
])
sinclude(acx_pthread.m4)
sinclude(binreloc.m4)
@ -458,14 +470,11 @@ if test "$CFLAGS" = "-g -O2" -o "$CFLAGS" = "-g" -o "$CFLAGS" = "-O2"; then
fi
dnl Find out how to use threads on this platform
pre_acx_pthread_cflags=$CFLAGS
pre_acx_pthread_cxxflags=$CXXFLAGS
pre_acx_pthread_libs=$LIBS
XE_SAVE_ENV()
ACX_PTHREAD([
AC_DEFINE(HAVE_MULTI_THREAD, 1,
[Define this if multi-threading should be supported])])
CFLAGS=$pre_acx_pthread_cflags
LIBS=$pre_acx_pthread_libs
XE_RESTORE_ENV()
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
@ -507,7 +516,7 @@ AC_ARG_WITH(system-editline,
# not need editline in default libs, but need to test for its presence
READLINE=edit # builtin default
saveLIBS=$LIBS
XE_SAVE_ENV()
if test "$STD_EDITLINE" = "true"; then
AC_CHECK_LIB(edit, readline, [READLINE=edit EDITLINE_FLG=Y],
AC_CHECK_LIB(editline, readline, [READLINE=editline EDITLINE_FLG=Y],
@ -517,7 +526,7 @@ if test "$STD_EDITLINE" = "true"; then
AC_MSG_WARN([[[--with-system-editline specified, not found. Using bundled editline]]])])))
fi
fi
LIBS=$saveLIBS
XE_RESTORE_ENV()
AC_SUBST(READLINE)
AC_SUBST(STD_EDITLINE)
@ -671,6 +680,14 @@ AC_CHECK_HEADER(unicode/ucnv.h,,AC_MSG_ERROR(ICU support not found - please inst
dnl setting ICU_OK here is done to only avoid default action
AC_CHECK_LIB(icuuc, main, ICU_OK=yes, AC_MSG_ERROR(ICU support not found - please install development ICU package))
dnl check for tommath presence
XE_SAVE_ENV()
LIBS=
AC_CHECK_HEADER(tommath.h,,AC_MSG_ERROR(Include file for tommath not found - please install development tommath package))
AC_CHECK_LIB(tommath, mp_init, MATHLIB=-ltommath, AC_MSG_ERROR(Library tommath not found - please install development tommath package))
XE_RESTORE_ENV()
AC_SUBST(MATHLIB)
dnl Check for libraries
AC_SEARCH_LIBS(dlopen, dl)
AC_CHECK_LIB(m, main)
@ -990,12 +1007,12 @@ case "$PLATFORM" in
esac
dnl Detect support for ISO syntax for thread-locals
pre_tls_cxxflags=$CXXFLAGS
XE_SAVE_ENV()
CXXFLAGS=$TLS_OPTIONS
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[__thread int a = 42;]],[[a = a + 1;]])],
AC_DEFINE(HAVE___THREAD, 1, [Define it if compiler supports ISO syntax for thread-local storage]),)
CXXFLAGS=$pre_tls_cxxflags
XE_RESTORE_ENV()
AC_SUBST(TLS_OPTIONS)
AC_SUBST(ATOMIC_OPTIONS)
AC_SUBST(CAS_OPTIONS)

View File

@ -1468,6 +1468,8 @@ C --
PARAMETER (GDS__ee_blr_mismatch_length = 335545027)
INTEGER*4 GDS__ss_out_of_bounds
PARAMETER (GDS__ss_out_of_bounds = 335545028)
INTEGER*4 GDS__missing_data_structures
PARAMETER (GDS__missing_data_structures = 335545029)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -741,6 +741,7 @@ const
gds_ee_blr_mismatch_null = 335545026;
gds_ee_blr_mismatch_length = 335545027;
gds_ss_out_of_bounds = 335545028;
gds_missing_data_structures = 335545029;
gds_gfix_db_name = 335740929;
gds_gfix_invalid_sw = 335740930;
gds_gfix_incmp_sw = 335740932;

View File

@ -56,10 +56,10 @@ DebugServer::DebugServer(Firebird::IPluginConfig*)
: str(getPool())
{ }
Result FB_CARG DebugServer::startAuthentication(Firebird::IStatus* status, const AuthTags* tags,
IClumplets* dpb, IWriter* writerInterface)
Result FB_CARG DebugServer::authenticate(Firebird::IStatus* status, IServerBlock* sBlock,
IWriter* writerInterface)
{
try
/* try
{
Firebird::MasterInterfacePtr()->upgradeInterface(dpb, FB_AUTH_CLUMPLETS_VERSION, upInfo);
str.erase();
@ -86,10 +86,10 @@ Result FB_CARG DebugServer::startAuthentication(Firebird::IStatus* status, const
catch (const Firebird::Exception& ex)
{
ex.stuffException(status);
return AUTH_FAILED;
}
} */
return AUTH_FAILED;
}
/*
Result FB_CARG DebugServer::contAuthentication(Firebird::IStatus* status, const unsigned char* data,
unsigned int size, IWriter* writerInterface)
{
@ -108,15 +108,7 @@ Result FB_CARG DebugServer::contAuthentication(Firebird::IStatus* status, const
return AUTH_FAILED;
}
}
void FB_CARG DebugServer::getData(const unsigned char** data, unsigned short* dataSize)
{
*data = reinterpret_cast<const unsigned char*>(str.c_str());
*dataSize = str.length();
#ifdef AUTH_VERBOSE
fprintf(stderr, "DebugServer::getData: %.*s\n", *dataSize, *data);
#endif
}
*/
int FB_CARG DebugServer::release()
{
@ -133,8 +125,9 @@ DebugClient::DebugClient(Firebird::IPluginConfig*)
: str(getPool())
{ }
Result FB_CARG DebugClient::startAuthentication(Firebird::IStatus* status, const AuthTags* tags, IClumplets* dpb)
Result FB_CARG DebugClient::authenticate(Firebird::IStatus* status, IClientBlock* cBlock)
{
/*
try
{
str = "HAND";
@ -155,10 +148,11 @@ Result FB_CARG DebugClient::startAuthentication(Firebird::IStatus* status, const
catch (const Firebird::Exception& ex)
{
ex.stuffException(status);
return AUTH_FAILED;
}
*/
return AUTH_FAILED;
}
/*
Result FB_CARG DebugClient::contAuthentication(Firebird::IStatus* status, const unsigned char* data, unsigned int size)
{
try
@ -180,15 +174,7 @@ Result FB_CARG DebugClient::contAuthentication(Firebird::IStatus* status, const
return AUTH_FAILED;
}
}
void FB_CARG DebugClient::getData(const unsigned char** data, unsigned short* dataSize)
{
*data = reinterpret_cast<const unsigned char*>(str.c_str());
*dataSize = str.length();
#ifdef AUTH_VERBOSE
fprintf(stderr, "DebugClient::getData: %.*s\n", *dataSize, *data);
#endif
}
*/
int FB_CARG DebugClient::release()
{
@ -201,6 +187,22 @@ int FB_CARG DebugClient::release()
return 1;
}
Result DebugServer::getSessionKey(Firebird::IStatus*,
const unsigned char** key, unsigned int* keyLen)
{
*key = NULL;
*keyLen = 0;
return AUTH_CONTINUE;
}
Result DebugClient::getSessionKey(Firebird::IStatus*,
const unsigned char** key, unsigned int* keyLen)
{
*key = NULL;
*keyLen = 0;
return AUTH_CONTINUE;
}
} // namespace Auth
#endif // AUTH_DEBUG

View File

@ -34,7 +34,7 @@
#ifdef AUTH_DEBUG
#include "../auth/AuthInterface.h"
#include "firebird/Auth.h"
#include "../common/classes/ImplementHelper.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/init.h"
@ -51,11 +51,10 @@ class DebugServer : public Firebird::StdPlugin<IServer, FB_AUTH_SERVER_VERSION>
public:
DebugServer(Firebird::IPluginConfig*);
Result startAuthentication(Firebird::IStatus* status, const AuthTags* tags, IClumplets* dpb,
Result authenticate(Firebird::IStatus* status, IServerBlock* sBlock,
IWriter* writerInterface);
Result contAuthentication(Firebird::IStatus* status, const unsigned char* data,
unsigned int size, IWriter* writerInterface);
void getData(const unsigned char** data, unsigned short* dataSize);
Result getSessionKey(Firebird::IStatus* status,
const unsigned char** key, unsigned int* keyLen);
int release();
private:
@ -67,9 +66,9 @@ class DebugClient : public Firebird::StdPlugin<IClient, FB_AUTH_CLIENT_VERSION>
public:
DebugClient(Firebird::IPluginConfig*);
Result startAuthentication(Firebird::IStatus* status, const AuthTags* tags, IClumplets* dpb);
Result contAuthentication(Firebird::IStatus* status, const unsigned char* data, unsigned int size);
void getData(const unsigned char** data, unsigned short* dataSize);
Result authenticate(Firebird::IStatus* status, IClientBlock* sBlock);
Result getSessionKey(Firebird::IStatus* status,
const unsigned char** key, unsigned int* keyLen);
int release();
private:

View File

@ -0,0 +1,212 @@
/*
* PROGRAM: Firebird interface.
* MODULE: BigInteger.cpp
* DESCRIPTION: Integer of unlimited precision. Uses libtommath.
*
* 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 Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2011 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#include "firebird.h"
#include "gen/iberror.h"
#include <stdlib.h>
#include "../auth/SecureRemotePassword/BigInteger.h"
#include "../common/os/guid.h"
using namespace Firebird;
#define CHECK_MP(a) check(a, #a)
namespace Auth
{
static inline void check(int rc, const char* function)
{
switch (rc)
{
case MP_OKAY:
return;
case MP_MEM:
BadAlloc::raise();
default:
// Want fancy "Libtommath error in @1 code @2"
(Arg::Gds(isc_random) << "Libtommath error").raise();
}
}
BigInteger::BigInteger()
{
CHECK_MP(mp_init(&t));
}
BigInteger::BigInteger(const char* text, unsigned int radix)
{
CHECK_MP(mp_init(&t));
CHECK_MP(mp_read_radix(&t, text, radix));
}
BigInteger::BigInteger(unsigned int count, const unsigned char* bytes)
{
CHECK_MP(mp_init(&t));
assign(count, bytes);
}
BigInteger::BigInteger(const Firebird::UCharBuffer& val)
{
CHECK_MP(mp_init(&t));
assign(val.getCount(), val.begin());
}
BigInteger::BigInteger(const BigInteger& val)
{
CHECK_MP(mp_init_copy(const_cast<mp_int*>(&val.t), &t));
}
BigInteger::~BigInteger()
{
mp_clear(&t);
}
BigInteger& BigInteger::operator= (const BigInteger& val)
{
CHECK_MP(mp_copy(const_cast<mp_int*>(&val.t), &t));
return *this;
}
void BigInteger::random(int numBytes)
{
Firebird::UCharBuffer b;
Firebird::GenerateRandomBytes(b.getBuffer(numBytes), numBytes);
assign(numBytes, b.begin());
}
void BigInteger::assign(unsigned int count, const unsigned char* bytes)
{
CHECK_MP(mp_read_unsigned_bin(&t, bytes, count));
}
BigInteger BigInteger::operator+ (const BigInteger& val) const
{
BigInteger rc;
CHECK_MP(mp_add(const_cast<mp_int*>(&t), const_cast<mp_int*>(&val.t), &rc.t));
return rc;
}
BigInteger BigInteger::operator- (const BigInteger& val) const
{
BigInteger rc;
CHECK_MP(mp_sub(const_cast<mp_int*>(&t), const_cast<mp_int*>(&val.t), &rc.t));
return rc;
}
BigInteger BigInteger::operator* (const BigInteger& val) const
{
BigInteger rc;
CHECK_MP(mp_mul(const_cast<mp_int*>(&t), const_cast<mp_int*>(&val.t), &rc.t));
return rc;
}
BigInteger BigInteger::operator/ (const BigInteger& val) const
{
BigInteger rc;
CHECK_MP(mp_div(const_cast<mp_int*>(&t), const_cast<mp_int*>(&val.t), &rc.t, NULL));
return rc;
}
BigInteger BigInteger::operator% (const BigInteger& val) const
{
BigInteger rc;
CHECK_MP(mp_mod(const_cast<mp_int*>(&t), const_cast<mp_int*>(&val.t), &rc.t));
return rc;
}
BigInteger& BigInteger::operator+= (const BigInteger& val)
{
CHECK_MP(mp_add(&t, const_cast<mp_int*>(&val.t), &t));
return *this;
}
BigInteger& BigInteger::operator-= (const BigInteger& val)
{
CHECK_MP(mp_sub(&t, const_cast<mp_int*>(&val.t), &t));
return *this;
}
BigInteger& BigInteger::operator*= (const BigInteger& val)
{
CHECK_MP(mp_mul(&t, const_cast<mp_int*>(&val.t), &t));
return *this;
}
BigInteger& BigInteger::operator/= (const BigInteger& val)
{
CHECK_MP(mp_div(&t, const_cast<mp_int*>(&val.t), &t, NULL));
return *this;
}
BigInteger& BigInteger::operator%= (const BigInteger& val)
{
CHECK_MP(mp_mod(&t, const_cast<mp_int*>(&val.t), &t));
return *this;
}
bool BigInteger::operator== (const BigInteger& val) const
{
return mp_cmp(const_cast<mp_int*>(&t), const_cast<mp_int*>(&val.t)) == 0;
}
void BigInteger::getBytes(Firebird::UCharBuffer& bytes) const
{
CHECK_MP(mp_to_unsigned_bin(const_cast<mp_int*>(&t), bytes.getBuffer(length())));
}
unsigned int BigInteger::length() const
{
int rc = mp_unsigned_bin_size(const_cast<mp_int*>(&t));
if (rc < 0)
{
check(rc, "mp_unsigned_bin_size(&t)");
}
return static_cast<unsigned int>(rc);
}
void BigInteger::getText(string& str, unsigned int radix) const
{
int size;
CHECK_MP(mp_radix_size(const_cast<mp_int*>(&t), radix, &size));
str.resize(size - 1, ' ');
CHECK_MP(mp_toradix(const_cast<mp_int*>(&t), const_cast<char*>(str.c_str()), radix));
}
BigInteger BigInteger::modPow(const BigInteger& pow, const BigInteger& mod) const
{
BigInteger rc;
CHECK_MP(mp_exptmod(const_cast<mp_int*>(&t), const_cast<mp_int*>(&pow.t),
const_cast<mp_int*>(&mod.t), &rc.t));
return rc;
}
}
#undef CHECK_MP

View File

@ -0,0 +1,80 @@
/*
* PROGRAM: Firebird interface.
* MODULE: BigInteger.h
* DESCRIPTION: Integer of unlimited precision. Uses libtommath.
*
* 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 Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2010 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#ifndef FB_COMMON_CLASSES_BIG_INTEGER
#define FB_COMMON_CLASSES_BIG_INTEGER
#include <tommath.h>
#include "../common/classes/fb_string.h"
#include "../common/classes/array.h"
namespace Auth {
class BigInteger
{
public:
BigInteger();
BigInteger(const char* text, unsigned int radix = 16u);
BigInteger(unsigned int count, const unsigned char* bytes);
BigInteger(const Firebird::UCharBuffer& val);
BigInteger(const BigInteger& val);
// BigInteger(int numBits, Random& r);
~BigInteger();
BigInteger& operator= (const BigInteger& val);
void random(int numBytes);
void assign(unsigned int count, const unsigned char* bytes);
BigInteger operator+ (const BigInteger& val) const;
BigInteger operator- (const BigInteger& val) const;
BigInteger operator* (const BigInteger& val) const;
BigInteger operator/ (const BigInteger& val) const;
BigInteger operator% (const BigInteger& val) const;
BigInteger& operator+= (const BigInteger& val);
BigInteger& operator-= (const BigInteger& val);
BigInteger& operator*= (const BigInteger& val);
BigInteger& operator/= (const BigInteger& val);
BigInteger& operator%= (const BigInteger& val);
bool operator== (const BigInteger& val) const;
void getBytes(Firebird::UCharBuffer& bytes) const;
unsigned int length() const;
void getText(Firebird::string& str, unsigned int radix = 16u) const;
BigInteger modPow(const BigInteger& pow, const BigInteger& mod) const;
private:
mp_int t;
};
} // namespace Firebird
#endif // FB_COMMON_CLASSES_BIG_INTEGER

View File

@ -0,0 +1,157 @@
#include "../jrd/align.h"
#include "../common/classes/alloc.h"
// This class helps to fill FbMessage with correct values
class Message : public Firebird::FbMessage, public Firebird::GlobalStorage
{
public:
Message()
: blrBuf(getPool()), dataBuf(getPool())
{
blrLength = 0;
blr = NULL;
bufferLength = 0;
buffer = NULL;
// start message BLR
blrBuf.add(blr_version5);
blrBuf.add(blr_begin);
blrBuf.add(blr_message);
blrBuf.add(0);
countOffset = blrBuf.getCount();
blrBuf.add(0);
blrBuf.add(0);
varCount = 0;
}
template <typename T>
unsigned genBlr()
{
// for special types call type-specific BLR generator
// for generic types use specialization of whole call
return T::genBlr(blrBuf);
}
template <typename T>
void add(unsigned& pos, unsigned& null)
{
if (blr)
{
(Firebird::Arg::Gds(isc_random) << "This is already constructed message").raise();
}
// generate code for variable
unsigned align = genBlr<T>();
if (align)
{
bufferLength = FB_ALIGN(bufferLength, align);
}
pos = bufferLength;
bufferLength += sizeof(T);
// generate code for null flag
blrBuf.add(blr_short);
blrBuf.add(0);
align = type_alignments[dtype_short];
if (align)
{
bufferLength = FB_ALIGN(bufferLength, align);
}
null = bufferLength;
bufferLength += sizeof(short);
++varCount;
}
void ready()
{
if (blr)
return;
// Adjust number of variables
blrBuf[countOffset] = (varCount * 2) & 0xFF;
blrBuf[countOffset + 1] = ((varCount * 2) >> 8) & 0xFF;
// Complete blr
blrBuf.add(blr_end);
blrBuf.add(blr_eoc);
blrLength = blrBuf.getCount();
blr = blrBuf.begin();
// Allocate buffer
buffer = dataBuf.getBuffer(bufferLength);
}
Firebird::UCharBuffer blrBuf, dataBuf;
unsigned countOffset, varCount;
};
template <>
unsigned Message::genBlr<SLONG>()
{
blrBuf.add(blr_long);
blrBuf.add(0); // scale
return type_alignments[dtype_long];
}
// With template magic, we make the fields strongly-typed.
template <class T>
class Field
{
public:
Field(Message& m)
: msg(m), pos(~0), nullPos(~0)
{
msg.add<T>(pos, nullPos);
}
T& operator()()
{
msg.ready();
return *(T*) (msg.buffer + pos);
}
short& null()
{
msg.ready();
return *(short*) (msg.buffer + nullPos);
}
private:
Message& msg;
unsigned pos, nullPos;
};
template <short N>
class VarChar
{
public:
short len;
char data[N]; // This guarantees N > 0
static unsigned genBlr(Firebird::UCharBuffer& blr)
{
blr.add(blr_varying);
blr.add(N & 0xFF);
blr.add((N >> 8) & 0xFF);
return type_alignments[dtype_varying];
}
const VarChar& operator=(const char* str)
{
strncpy(data, str, N);
len = strlen(str);
if (len > N)
len = N;
return *this;
}
void set(unsigned short l, void* bytes)
{
if (l > (unsigned short) N)
l = N;
memcpy(data, bytes, l);
len = l;
}
};

View File

@ -0,0 +1,173 @@
/*
* PROGRAM: Firebird authentication.
* MODULE: SrpClient.cpp
* DESCRIPTION: SPR authentication plugin.
*
* 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 Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2011 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include "../auth/SecureRemotePassword/client/SrpClient.h"
#include "../auth/SecureRemotePassword/srp.h"
#include "../common/classes/ImplementHelper.h"
using namespace Firebird;
namespace Auth {
class SrpClient : public Firebird::StdPlugin<IClient, FB_AUTH_CLIENT_VERSION>
{
public:
explicit SrpClient(Firebird::IPluginConfig*)
: client(NULL), data(getPool()),
sessionKey(getPool())
{ }
// IClient implementation
Result FB_CARG authenticate(Firebird::IStatus*, IClientBlock* cb);
Result FB_CARG getSessionKey(Firebird::IStatus* status,
const unsigned char** key, unsigned int* keyLen);
int FB_CARG release();
private:
RemotePassword* client;
string data;
UCharBuffer sessionKey;
};
Result SrpClient::authenticate(Firebird::IStatus* status, IClientBlock* cb)
{
try
{
if (sessionKey.hasData())
{
// Why are we called when auth is completed?
(Firebird::Arg::Gds(isc_random) << "Auth sync failure - SRP's authenticate called more times than supported").raise();
}
if (!client)
{
HANDSHAKE_DEBUG(fprintf(stderr, "Cln SRP1: %s %s\n", cb->getLogin(), cb->getPassword()));
if (!(cb->getLogin() && cb->getPassword()))
{
return AUTH_CONTINUE;
}
client = new RemotePassword;
client->genClientKey(data);
dumpIt("Clnt: clientPubKey", data);
cb->putData(data.length(), data.begin());
return AUTH_MORE_DATA;
}
HANDSHAKE_DEBUG(fprintf(stderr, "Cln SRP2\n"));
unsigned int length;
const unsigned char* saltAndKey = cb->getData(&length);
if (length > (RemotePassword::SRP_SALT_SIZE + RemotePassword::SRP_KEY_SIZE + 2) * 2)
{
string msg;
msg.printf("Wrong length (%d) of data from server", length);
(Arg::Gds(isc_random) << msg).raise();
}
string salt, key;
unsigned charSize = *saltAndKey++;
charSize += ((unsigned)*saltAndKey++) << 8;
if (charSize > RemotePassword::SRP_SALT_SIZE * 2)
{
string msg;
msg.printf("Wrong length (%d) of salt from server", charSize);
(Arg::Gds(isc_random) << msg).raise();
}
salt.assign(saltAndKey, charSize);
dumpIt("Clnt: salt", salt);
saltAndKey += charSize;
length -= (charSize + 2);
charSize = *saltAndKey++;
charSize += ((unsigned)*saltAndKey++) << 8;
if (charSize + 2 != length)
{
string msg;
msg.printf("Wrong length (%d) of key from server", charSize);
(Arg::Gds(isc_random) << msg).raise();
}
key.assign(saltAndKey, charSize);
dumpIt("Clnt: key(srvPub)", key);
dumpIt("Clnt: login", string(cb->getLogin()));
dumpIt("Clnt: pass", string(cb->getPassword()));
client->clientSessionKey(sessionKey, cb->getLogin(), salt.c_str(), cb->getPassword(), key.c_str());
dumpIt("Clnt: sessionKey", sessionKey);
BigInteger cProof = client->clientProof(cb->getLogin(), salt.c_str(), sessionKey);
cProof.getText(data);
cb->putData(data.length(), data.c_str());
}
catch(const Exception& ex)
{
ex.stuffException(status);
return AUTH_FAILED;
}
return AUTH_SUCCESS;
}
Result SrpClient::getSessionKey(Firebird::IStatus*,
const unsigned char** key, unsigned int* keyLen)
{
if (!sessionKey.hasData())
{
return AUTH_MORE_DATA;
}
*key = sessionKey.begin();
*keyLen = sessionKey.getCount();
return AUTH_SUCCESS;
}
int SrpClient::release()
{
if (--refCounter == 0)
{
delete this;
return 0;
}
return 1;
}
namespace
{
Firebird::SimpleFactory<SrpClient> factory;
}
void registerSrpClient(Firebird::IPluginManager* iPlugin)
{
iPlugin->registerPluginFactory(PluginType::AuthClient, RemotePassword::plugName, &factory);
}
} // namespace Auth

View File

@ -0,0 +1,38 @@
/*
* PROGRAM: Firebird authentication.
* MODULE: SrpClient.h
* DESCRIPTION: SPR authentication plugin.
*
* 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 Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2011 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef AUTH_SRP_CLIENT_H
#define AUTH_SRP_CLIENT_H
#include "firebird/Auth.h"
namespace Auth {
void registerSrpClient(Firebird::IPluginManager* iPlugin);
} // namespace Auth
#endif // AUTH_SRP_CLIENT_H

View File

@ -0,0 +1,633 @@
/*
* PROGRAM: Firebird authentication
* MODULE: SrpManagement.cpp
* DESCRIPTION: Manages security database with SRP
*
* 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 Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2011 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include "../common/classes/ImplementHelper.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/StatusHolder.h"
#include "firebird/Auth.h"
#include "../auth/SecureRemotePassword/srp.h"
#include "../jrd/constants.h"
#include "../utilities/gsec/gsec.h"
#include "../auth/SecureRemotePassword/Message.h"
#include "../common/classes/auto.h"
namespace {
Firebird::MakeUpgradeInfo<> upInfo;
const unsigned int INIT_KEY = ((~0) - 1);
unsigned int secDbKey = INIT_KEY;
const unsigned int SZ_LOGIN = 31;
const unsigned int SZ_NAME = 31;
template <short N>
void setField(Field<VarChar<N> >& to, Auth::ICharUserField* from)
{
if (from->entered())
{
to() = from->get();
to.null() = 0;
}
else
{
to.null() = -1;
}
}
// Domains
typedef Field<VarChar<SZ_LOGIN> > Login;
typedef Field<VarChar<Auth::RemotePassword::SRP_VERIFIER_SIZE> > Verifier;
typedef Field<VarChar<Auth::RemotePassword::SRP_SALT_SIZE> > Salt;
typedef Field<VarChar<SZ_NAME> > Name;
void allocField(Firebird::AutoPtr<Name>& field, Message& up, Auth::ICharUserField* value, Firebird::string& update, const char* name)
{
if (value->entered() || value->specified())
{
field = new Name(up);
update += ' ';
update += name;
update += "=?,";
}
}
void assignField(Firebird::AutoPtr<Name>& field, Auth::ICharUserField* name)
{
if (field.hasData())
{
if (name->entered())
{
(*field)() = name->get();
field->null() = 0;
}
else
{
fb_assert(name->specified());
field->null() = -1;
}
}
}
template <short N>
void listField(Auth::ICharUserField* to, Field<VarChar<N> >& from)
{
to->set(from().data);
to->setEntered(from.null() == 0 ? 1 : 0);
}
}
namespace Auth {
class SrpManagement : public Firebird::StdPlugin<IManagement, FB_AUTH_MANAGE_VERSION>
{
public:
explicit SrpManagement(Firebird::IPluginConfig* par)
: config(par->getFirebirdConf())
{
config->release();
}
void prepareDataStructures()
{
const char* script[] = {
"CREATE TABLE PLG$SRP (PLG$USER_NAME SEC$USER_NAME NOT NULL PRIMARY KEY, "
"PLG$VERIFIER VARCHAR(128) CHARACTER SET OCTETS NOT NULL, "
"PLG$SALT VARCHAR(32) CHARACTER SET OCTETS NOT NULL, "
"PLG$COMMENT RDB$DESCRIPTION, PLG$FIRST SEC$NAME_PART, "
"PLG$MIDDLE SEC$NAME_PART, PLG$LAST SEC$NAME_PART)" ,
"CREATE VIEW PLG$SRP_VIEW AS "
"SELECT PLG$USER_NAME, PLG$VERIFIER, PLG$SALT, PLG$COMMENT, PLG$FIRST, PLG$MIDDLE, PLG$LAST "
"FROM PLG$SRP WHERE CURRENT_USER = 'SYSDBA' OR CURRENT_ROLE = 'RDB$ADMIN' OR CURRENT_USER = PLG$SRP.PLG$USER_NAME",
"GRANT ALL ON PLG$SRP to VIEW PLG$SRP_VIEW",
"GRANT SELECT ON PLG$SRP_VIEW to PUBLIC",
"GRANT UPDATE(PLG$VERIFIER, PLG$SALT, PLG$FIRST, PLG$MIDDLE, PLG$LAST) ON PLG$SRP_VIEW TO PUBLIC",
NULL };
Firebird::LocalStatus s;
Firebird::RefPtr<Firebird::ITransaction> ddlTran(att->startTransaction(&s, 0, NULL));
if (!s.isSuccess())
{
Firebird::status_exception::raise(s.get());
}
try
{
for (const char** sql = script; *sql; ++sql)
{
att->execute(&s, ddlTran, 0, *sql, 3, 0, NULL, NULL);
if (!s.isSuccess())
{
Firebird::status_exception::raise(s.get());
}
}
ddlTran->commit(&s);
if (!s.isSuccess())
{
Firebird::status_exception::raise(s.get());
}
}
catch (const Firebird::Exception&)
{
if (ddlTran)
{
ddlTran->rollback(&s);
}
throw;
}
}
// IManagement implementation
void FB_CARG start(Firebird::IStatus* status, ILogonInfo* logonInfo)
{
try
{
Firebird::MasterInterfacePtr()->upgradeInterface(logonInfo, FB_AUTH_LOGON_INFO_VERSION, upInfo);
status->init();
if (att)
{
(Firebird::Arg::Gds(isc_random) << "Database is already attached in SRP").raise();
}
if (secDbKey == INIT_KEY)
{
secDbKey = config->getKey("SecurityDatabase");
}
const char* secDbName = config->asString(secDbKey);
if (!(secDbName && secDbName[0]))
{
(Firebird::Arg::Gds(isc_random) << "Error getting security database name").raise();
}
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::dpbList, MAX_DPB_SIZE);
dpb.insertByte(isc_dpb_gsec_attach, TRUE);
const unsigned char* authBlock;
unsigned int authBlockSize = logonInfo->authBlock(&authBlock);
if (authBlockSize)
dpb.insertBytes(isc_dpb_auth_block, authBlock, authBlockSize);
else
{
const char* str = logonInfo->name();
if (str && str[0])
dpb.insertString(isc_dpb_trusted_auth, str, strlen(str));
str = logonInfo->role();
if (str && str[0])
dpb.insertString(isc_dpb_sql_role_name, str, strlen(str));
else if (logonInfo->forceAdmin())
dpb.insertString(isc_dpb_trusted_role, ADMIN_ROLE, strlen(ADMIN_ROLE));
}
Firebird::RefPtr<Firebird::IProvider> p(Firebird::MasterInterfacePtr()->getDispatcher());
p->release();
att = p->attachDatabase(status, secDbName, dpb.getBufferLength(), dpb.getBuffer());
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
tra = att->startTransaction(status, 0, NULL);
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
}
catch (const Firebird::Exception& ex)
{
ex.stuffException(status);
if (att)
{
// detach from database
Firebird::LocalStatus lStatus;
att->detach(&lStatus);
att = NULL;
}
}
}
int FB_CARG execute(Firebird::IStatus* status, IUser* user, IListUsers* callback)
{
try
{
Firebird::MasterInterfacePtr()->upgradeInterface(callback, FB_AUTH_LIST_USERS_VERSION, upInfo);
Firebird::MasterInterfacePtr()->upgradeInterface(user, FB_AUTH_USER_VERSION, upInfo);
status->init();
fb_assert(att);
fb_assert(tra);
switch(user->operation())
{
case MAP_DROP_OPER:
case MAP_SET_OPER:
{
Firebird::string sql;
sql.printf("ALTER ROLE RDB$ADMIN %s AUTO ADMIN MAPPING",
user->operation() == MAP_SET_OPER ? "SET" : "DROP");
att->execute(status, tra, sql.length(), sql.c_str(), 3, 0, NULL, NULL);
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
}
break;
case ADD_OPER:
{
const char* insert =
"INSERT INTO plg$srp_view(PLG$USER_NAME, PLG$VERIFIER, PLG$SALT, PLG$FIRST, PLG$MIDDLE, PLG$LAST) "
"VALUES(?, ?, ?, ?, ?, ?)";
Message add;
Login login(add);
Verifier verifier(add);
Salt slt(add);
Name first(add), middle(add), last(add);
setField(login, user->userName());
setField(first, user->firstName());
setField(middle, user->middleName());
setField(last, user->lastName());
#if SRP_DEBUG > 1
BigInteger salt("02E268803000000079A478A700000002D1A6979000000026E1601C000000054F");
#else
BigInteger salt;
salt.random(RemotePassword::SRP_SALT_SIZE);
#endif
Firebird::UCharBuffer s;
salt.getBytes(s);
slt().set(s.getCount(), s.begin());
slt.null() = 0;
dumpIt("salt", s);
#if SRP_DEBUG > 0
fprintf(stderr, ">%s< >%s<\n", user->userName()->get(), user->password()->get());
#endif
Firebird::string s1;
salt.getText(s1);
server.computeVerifier(user->userName()->get(), s1, user->password()->get()).getBytes(s);
dumpIt("verifier", s);
verifier().set(s.getCount(), s.begin());
verifier.null() = 0;
for (unsigned repeat = 0; ; ++repeat)
{
att->execute(status, tra, 0, insert, 3, 0, &add, NULL);
if (status->isSuccess() || repeat > 0)
{
break;
}
const ISC_STATUS* v = status->get();
while (v[0] == isc_arg_gds)
{
if (v[1] == isc_dsql_relation_err)
{
prepareDataStructures();
tra->commit(status);
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
tra = att->startTransaction(status, 0, NULL);
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
break;
}
do
{
v += 2;
} while (v[0] != isc_arg_warning && v[0] != isc_arg_gds && v[0] != isc_arg_end);
}
}
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
}
break;
case MOD_OPER:
{
Message up;
Firebird::string update = "UPDATE plg$srp_view SET ";
Firebird::AutoPtr<Verifier> verifier;
Firebird::AutoPtr<Salt> slt;
if (user->password()->entered())
{
verifier = new Verifier(up);
slt = new Salt(up);
update += "PLG$VERIFIER=?,PLG$SALT=?,";
}
Firebird::AutoPtr<Name> first, middle, last;
allocField(first, up, user->firstName(), update, "PLG$FIRST");
allocField(middle, up, user->middleName(), update, "PLG$MIDDLE");
allocField(last, up, user->lastName(), update, "PLG$LAST");
if (update[update.length() - 1] != ',')
{
return 0;
}
update.rtrim(",");
update += " WHERE PLG$USER_NAME=?";
Login login(up);
if (verifier.hasData())
{
#if SRP_DEBUG > 1
BigInteger salt("02E268803000000079A478A700000002D1A6979000000026E1601C000000054F");
#else
BigInteger salt;
salt.random(RemotePassword::SRP_SALT_SIZE);
#endif
Firebird::UCharBuffer s;
salt.getBytes(s);
(*slt)().set(s.getCount(), s.begin());
slt->null() = 0;
dumpIt("salt", s);
#if SRP_DEBUG > 0
fprintf(stderr, ">%s< >%s<\n", user->userName()->get(), user->password()->get());
#endif
Firebird::string s1;
salt.getText(s1);
server.computeVerifier(user->userName()->get(), s1, user->password()->get()).getBytes(s);
dumpIt("verifier", s);
(*verifier)().set(s.getCount(), s.begin());
verifier->null() = 0;
}
assignField(first, user->firstName());
assignField(middle, user->middleName());
assignField(last, user->lastName());
setField(login, user->userName());
att->execute(status, tra, 0, update.c_str(), 3, 0, &up, NULL);
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
}
break;
case DEL_OPER:
{
Message dl;
const char* del = "DELETE FROM plg$srp_view WHERE PLG$USER_NAME=?";
Login login(dl);
setField(login, user->userName());
att->execute(status, tra, 0, del, 3, 0, &dl, NULL);
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
}
break;
case OLD_DIS_OPER:
case DIS_OPER:
{
user->uid()->setEntered(0);
user->gid()->setEntered(0);
user->groupName()->setEntered(0);
user->password()->setEntered(0);
Message di;
Firebird::string disp = "SELECT PLG$USER_NAME, PLG$FIRST, PLG$MIDDLE, PLG$LAST, "
" CASE WHEN RDB$RELATION_NAME IS NULL THEN 0 ELSE 1 END "
"FROM PLG$SRP_VIEW LEFT JOIN RDB$USER_PRIVILEGES "
" ON PLG$SRP_VIEW.PLG$USER_NAME = RDB$USER_PRIVILEGES.RDB$USER "
" AND RDB$RELATION_NAME = 'RDB$ADMIN' "
" AND RDB$PRIVILEGE = 'M' ";
Firebird::AutoPtr<Message> par;
if (user->userName()->entered())
{
par = new Message;
Login login(*par);
setField(login, user->userName());
disp += " WHERE PLG$USER_NAME = ?";
}
printf("disp=%s\n", disp.c_str());
Login login(di);
Name first(di), middle(di), last(di);
Field<SLONG> admin(di);
di.ready();
Firebird::RefPtr<Firebird::IStatement> stmt;
try
{
stmt = att->allocateStatement(status);
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
stmt->prepare(status, tra, disp.length(), disp.c_str(), 3,
Firebird::IStatement::PREPARE_PREFETCH_NONE);
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
stmt->execute(status, tra, 0, par, NULL);
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
while (stmt->fetch(status, &di) == 0)
{
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
listField(user->userName(), login);
listField(user->firstName(), first);
listField(user->middleName(), middle);
listField(user->lastName(), last);
user->admin()->set(admin());
callback->list(user);
}
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
stmt->free(status, DSQL_drop);
if (!status->isSuccess())
{
Firebird::status_exception::raise(status->get());
}
}
catch(const Firebird::Exception&)
{
printf("Exception\n");
if (stmt.hasData())
{
stmt->release();
}
throw;
}
}
break;
default:
return -1;
}
}
catch (const Firebird::Exception& ex)
{
ex.stuffException(status);
return -1;
/*
switch(user->operation())
{
case ADD_OPER:
return GsecMsg19;
case MOD_OPER:
return GsecMsg20;
case DEL_OPER:
return GsecMsg23;
case OLD_DIS_OPER:
case DIS_OPER:
return GsecMsg28;
case MAP_DROP_OPER:
case MAP_SET_OPER:
return GsecMsg97;
default:
return GsecMsg17;
}
*/
}
return 0;
}
void FB_CARG commit(Firebird::IStatus* status)
{
if (tra)
{
tra->commit(status);
if (status->isSuccess())
{
tra = NULL;
}
}
}
void FB_CARG rollback(Firebird::IStatus* status)
{
if (tra)
{
tra->rollback(status);
if (status->isSuccess())
{
tra = NULL;
}
}
}
int FB_CARG release()
{
if (--refCounter == 0)
{
Firebird::LocalStatus status;
rollback(&status);
if (att)
{
att->detach(&status);
if (status.isSuccess())
{
att = NULL;
}
}
if (tra)
{
tra->release();
}
if (att)
{
att->release();
}
delete this;
return 0;
}
return 1;
}
private:
Firebird::RefPtr<Firebird::IFirebirdConf> config;
Firebird::RefPtr<Firebird::IAttachment> att;
Firebird::RefPtr<Firebird::ITransaction> tra;
RemotePassword server;
};
// register plugin
static Firebird::SimpleFactory<Auth::SrpManagement> factory;
} // namespace Auth
extern "C" void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master)
{
Firebird::PluginManagerInterfacePtr pi(master);
pi->registerPluginFactory(Firebird::PluginType::AuthUserManagement, Auth::RemotePassword::plugName, &Auth::factory);
Firebird::myModule->registerMe();
}

View File

@ -0,0 +1,48 @@
#include <tommath.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
int cb(unsigned char* dst, int len, void*)
{
static int f = -1;
if (f < 0)
{
f = open("/dev/urandom", 0);
if (f < 0)
{
perror("open /dev/urandom");
exit(1);
}
}
int rc = read(f, dst, len);
if (rc < 0)
{
perror("read /dev/urandom");
exit(1);
}
if (rc != len)
{
printf("Read %d from /dev/urandom instead %d\n", rc, len);
exit(1);
}
return rc;
}
main()
{
mp_int prime;
assert(mp_init(&prime) == 0);
int rc = mp_prime_random_ex(&prime, 256, 1024, LTM_PRIME_SAFE, cb, NULL);
assert(rc == 0);
int size;
assert(mp_radix_size(&prime, 16, &size) == 0);
char* rad = new char[size + 1];
assert(mp_toradix(&prime, rad, 16) == 0);
rad[size] = 0;
printf("%s\n", rad);
}

View File

@ -0,0 +1,13 @@
#!/bin/sh
compile()
{
file=test_${1}
g++ -I../../../include -DLINUX -DAMD64 -DDEV_BUILD ${file}.cpp \
../../../../temp/Debug/auth/SecureRemotePassword/srp.o \
../../../../temp/Debug/auth/SecureRemotePassword/BigInteger.o \
../../../../temp/Debug/common.a -ltommath ../../../../gen/Debug/firebird/lib/libfbclient.so \
-Wl,-rpath,../../../../gen/Debug/firebird/lib -lrt -o ${file} && ./${file}
}
compile srp
read x

View File

@ -0,0 +1,44 @@
#include "../auth/SecureRemotePassword/srp.h"
using namespace Auth;
int main(int argc, char** argv)
{
Firebird::string salt;
#if SRP_DEBUG > 1
BigInteger s("02E268803000000079A478A700000002D1A6979000000026E1601C000000054F");
#else
BigInteger s;
s.random(128);
#endif
s.getText(salt);
RemotePassword* server = new RemotePassword();
RemotePassword* client = new RemotePassword();
const char* account = "SYSDBA";
const char* password = "masterkey";
Firebird::UCharBuffer verifier;
dumpIt("salt", salt);
#if SRP_DEBUG > 0
fprintf(stderr, "%s %s\n", account, password);
#endif
server->computeVerifier(account, salt, password).getBytes(verifier);
dumpIt("verifier", verifier);
Firebird::string clientPubKey, serverPubKey;
client->genClientKey(clientPubKey);
fprintf(stderr, "C Pub %d\n", clientPubKey.length());
server->genServerKey(serverPubKey, verifier);
fprintf(stderr, "S Pub %d\n", serverPubKey.length());
Firebird::UCharBuffer key1, key2;
client->clientSessionKey(key1, account, salt.c_str(), argc > 1 ? argv[1] : password, serverPubKey.c_str());
server->serverSessionKey(key2, clientPubKey.c_str(), verifier);
BigInteger cProof = client->clientProof(account, salt.c_str(), key1);
BigInteger sProof = server->clientProof(account, salt.c_str(), key2);
printf("%s\n", cProof == sProof ? "OK" : "differ");
}

View File

@ -0,0 +1,321 @@
/*
* PROGRAM: Firebird authentication.
* MODULE: SrpServer.cpp
* DESCRIPTION: SPR authentication plugin.
*
* 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 Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2011 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include "../auth/SecureRemotePassword/client/SrpClient.h"
#include "../auth/SecureRemotePassword/srp.h"
#include "../common/classes/ImplementHelper.h"
#include "../common/classes/ClumpletWriter.h"
#include "../auth/SecureRemotePassword/Message.h"
using namespace Firebird;
namespace {
const unsigned int INIT_KEY = ((~0) - 1);
unsigned int secDbKey = INIT_KEY;
const unsigned int SZ_LOGIN = 31;
MakeUpgradeInfo<> upInfo;
}
namespace Auth {
class SrpServer : public StdPlugin<IServer, FB_AUTH_CLIENT_VERSION>
{
public:
explicit SrpServer(IPluginConfig* par)
: server(NULL), data(getPool()), account(getPool()),
clientPubKey(getPool()), serverPubKey(getPool()),
verifier(getPool()), salt(getPool()), sessionKey(getPool()),
config(par->getFirebirdConf()), secDbName(NULL)
{
config->release();
}
// IServer implementation
Result FB_CARG authenticate(IStatus* status, IServerBlock* sBlock, IWriter* writerInterface);
Result FB_CARG getSessionKey(Firebird::IStatus* status,
const unsigned char** key, unsigned int* keyLen);
int FB_CARG release();
private:
RemotePassword* server;
string data;
string account;
string clientPubKey, serverPubKey;
UCharBuffer verifier;
string salt;
UCharBuffer sessionKey;
RefPtr<IFirebirdConf> config;
const char *secDbName;
};
Result SrpServer::authenticate(IStatus* status, IServerBlock* sb, IWriter* writerInterface)
{
RefPtr<IAttachment> att;
RefPtr<ITransaction> tra;
RefPtr<IStatement> stmt;
try
{
if (!server)
{
HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP1\n"));
if (!sb->getLogin())
{
return AUTH_CONTINUE;
}
account = sb->getLogin();
account.upper();
unsigned int length;
const unsigned char* val = sb->getData(&length);
clientPubKey.assign(val, length);
if (!clientPubKey.hasData())
{
return AUTH_CONTINUE;
}
// read salt and verifier from database
// obviously we need something like attachments cache here
if (secDbKey == INIT_KEY)
{
secDbKey = config->getKey("SecurityDatabase");
}
secDbName = config->asString(secDbKey);
if (!(secDbName && secDbName[0]))
{
(Arg::Gds(isc_random) << "Error getting security database name").raise();
}
ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
dpb.insertByte(isc_dpb_sec_attach, TRUE);
const char* str = "SYSDBA";
dpb.insertString(isc_dpb_user_name, str, strlen(str));
RefPtr<IProvider> p(MasterInterfacePtr()->getDispatcher());
p->release();
att = p->attachDatabase(status, secDbName, dpb.getBufferLength(), dpb.getBuffer());
if (!status->isSuccess())
{
status_exception::raise(status->get());
}
HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP1: attached sec db %s\n", secDbName));
const UCHAR tpb[] =
{
isc_tpb_version1,
isc_tpb_read,
isc_tpb_read_committed,
isc_tpb_rec_version,
isc_tpb_wait
};
tra = att->startTransaction(status, sizeof(tpb), tpb);
if (!status->isSuccess())
{
status_exception::raise(status->get());
}
HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP1: started transaction\n"));
stmt = att->allocateStatement(status);
if (!status->isSuccess())
{
status_exception::raise(status->get());
}
const char* sql = "SELECT PLG$VERIFIER, PLG$SALT FROM PLG$SRP WHERE PLG$USER_NAME = ?";
stmt->prepare(status, tra, 0, sql, 3, 0);
if (!status->isSuccess())
{
const ISC_STATUS* v = status->get();
while (v[0] == isc_arg_gds)
{
if (v[1] == isc_dsql_relation_err)
{
Arg::Gds(isc_missing_data_structures).raise();
}
do
{
v += 2;
} while (v[0] != isc_arg_warning && v[0] != isc_arg_gds && v[0] != isc_arg_end);
}
status_exception::raise(status->get());
}
Message par;
Field <VarChar<SZ_LOGIN> > login(par);
login() = account.c_str();
login.null() = 0;
HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP1: Ready to run statement with login '%s'\n", account.c_str()));
Message dat;
Field <VarChar<RemotePassword::SRP_VERIFIER_SIZE> > verify(dat);
Field <VarChar<RemotePassword::SRP_SALT_SIZE> > slt(dat);
dat.ready();
stmt->execute(status, tra, 0, &par, &dat);
if (!status->isSuccess())
{
status_exception::raise(status->get());
}
HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP1: Executed statement\n"));
stmt->free(status, DSQL_drop);
if (!status->isSuccess())
{
status_exception::raise(status->get());
}
stmt = NULL;
tra->rollback(status);
if (!status->isSuccess())
{
status_exception::raise(status->get());
}
tra = NULL;
att->detach(status); // It will close statement
if (!status->isSuccess())
{
status_exception::raise(status->get());
}
att = NULL;
server = new RemotePassword;
verifier.assign(reinterpret_cast<UCHAR*>(verify().data), RemotePassword::SRP_VERIFIER_SIZE);
dumpIt("Srv: verifier", verifier);
UCharBuffer s;
s.assign(reinterpret_cast<UCHAR*>(slt().data), RemotePassword::SRP_SALT_SIZE);
BigInteger(s).getText(salt);
dumpIt("Srv: salt", salt);
server->genServerKey(serverPubKey, verifier);
// Ready to prepare data for client and calculate session key
data = "";
fb_assert(salt.length() <= RemotePassword::SRP_SALT_SIZE * 2);
data += char(salt.length());
data += char(salt.length() >> 8);
data.append(salt);
fb_assert(serverPubKey.length() <= RemotePassword::SRP_KEY_SIZE * 2);
data += char(serverPubKey.length());
data += char(serverPubKey.length() >> 8);
data.append(serverPubKey);
dumpIt("Srv: serverPubKey", serverPubKey);
dumpIt("Srv: data", data);
sb->putData(data.length(), data.c_str());
// Will be used to produce ISessionKey
dumpIt("Srv: clientPubKey", clientPubKey);
server->serverSessionKey(sessionKey, clientPubKey.c_str(), verifier);
dumpIt("Srv: sessionKey", sessionKey);
return AUTH_MORE_DATA;
}
unsigned int length;
const unsigned char* val = sb->getData(&length);
HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP2, data length is %d\n", length));
string proof;
proof.assign(val, length);
BigInteger clientProof(proof.c_str());
BigInteger serverProof = server->clientProof(account.c_str(), salt.c_str(), sessionKey);
if (clientProof == serverProof)
{
MasterInterfacePtr()->upgradeInterface(writerInterface, FB_AUTH_WRITER_VERSION, upInfo);
writerInterface->add(account.c_str());
writerInterface->setAttribute(AuthReader::AUTH_SECURE_DB, secDbName);
return AUTH_SUCCESS;
}
}
catch (const Exception& ex)
{
if (stmt)
{
stmt->free(status, DSQL_drop);
}
if (tra)
{
tra->rollback(status);
}
if (att)
{
att->detach(status);
}
status->init();
ex.stuffException(status);
}
return AUTH_FAILED;
}
Result SrpServer::getSessionKey(Firebird::IStatus*,
const unsigned char** key, unsigned int* keyLen)
{
if (!sessionKey.hasData())
{
return AUTH_MORE_DATA;
}
*key = sessionKey.begin();
*keyLen = sessionKey.getCount();
return AUTH_SUCCESS;
}
int SrpServer::release()
{
if (--refCounter == 0)
{
delete this;
return 0;
}
return 1;
}
namespace
{
SimpleFactory<SrpServer> factory;
}
void registerSrpServer(IPluginManager* iPlugin)
{
iPlugin->registerPluginFactory(PluginType::AuthServer, RemotePassword::plugName, &factory);
}
} // namespace Auth

View File

@ -0,0 +1,38 @@
/*
* PROGRAM: Firebird authentication.
* MODULE: SrpServer.h
* DESCRIPTION: SPR authentication plugin.
*
* 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 Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2011 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef AUTH_SRP_SERVER_H
#define AUTH_SRP_SERVER_H
#include "firebird/Auth.h"
namespace Auth {
void registerSrpServer(Firebird::IPluginManager* iPlugin);
} // namespace Auth
#endif // AUTH_SRP_SERVER_H

View File

@ -0,0 +1,221 @@
#include "firebird.h"
#include "gen/iberror.h"
#include "../auth/SecureRemotePassword/srp.h"
#include "../common/classes/alloc.h"
#include "../common/classes/ImplementHelper.h"
#include "../common/classes/init.h"
#include "../common/classes/fb_string.h"
#include "../common/sha.h"
using namespace Firebird;
namespace Auth {
class RemoteGroup
{
public:
Auth::BigInteger prime, generator, k;
private:
RemoteGroup(const char* primeString, const char* generatorString)
: prime(primeString), generator(generatorString), k()
{
Auth::Sha1 hash;
hash.processInt(prime);
if (prime.length() > generator.length())
{
unsigned int pad = prime.length() - generator.length();
char pb[1024];
memset(pb, 0, pad);
hash.process(pad, pb);
}
hash.processInt(generator);
hash.getInt(k);
}
static RemoteGroup group;
public:
static RemoteGroup* getGroup()
{
return &group;
}
};
const char* primeStr = "E67D2E994B2F900C3F41F08F5BB2627ED0D49EE1FE767A52EFCD565C"
"D6E768812C3E1E9CE8F0A8BEA6CB13CD29DDEBF7A96D4A93B55D488D"
"F099A15C89DCB0640738EB2CBDD9A8F7BAB561AB1B0DC1C6CDABF303"
"264A08D1BCA932D1F1EE428B619D970F342ABA9A65793B8B2F041AE5"
"364350C16F735F56ECBCA87BD57B29E7";
RemoteGroup RemoteGroup::group(primeStr, "02");
const char* RemotePassword::plugName = "Srp";
RemotePassword::RemotePassword()
: group(RemoteGroup::getGroup())
{
#if SRP_DEBUG > 1
privateKey = BigInteger("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DDDA2D4393");
#else
privateKey.random(RemotePassword::SRP_KEY_SIZE);
#endif
privateKey %= group->prime;
}
BigInteger RemotePassword::getUserHash(const char* account, const char* salt, const char* password)
{
hash.reset();
hash.process(account);
hash.process(":");
hash.process(password);
UCharBuffer hash1;
hash.getHash(hash1);
hash.reset();
hash.process(salt);
hash.process(hash1);
BigInteger rc;
hash.getInt(rc);
return rc;
}
BigInteger RemotePassword::computeVerifier(const string& account, const string& salt, const string& password)
{
BigInteger x(getUserHash(account.c_str(), salt.c_str(), password.c_str()));
return group->generator.modPow(x, group->prime);
}
void RemotePassword::genClientKey(string& pubkey)
{
dumpIt("privateKey(C)", privateKey);
clientPublicKey = group->generator.modPow(privateKey, group->prime);
clientPublicKey.getText(pubkey);
dumpIt("clientPublicKey", clientPublicKey);
}
void RemotePassword::genServerKey(string& pubkey, const Firebird::UCharBuffer& verifier)
{
dumpIt("privateKey(S)", privateKey);
BigInteger gb(group->generator.modPow(privateKey, group->prime)); // g^b
dumpIt("gb", gb);
BigInteger v(verifier); // v
BigInteger kv = (group->k * v) % group->prime;
dumpIt("kv", kv);
serverPublicKey = (kv + gb) % group->prime;
serverPublicKey.getText(pubkey);
dumpIt("serverPublicKey", serverPublicKey);
}
void RemotePassword::computeScramble()
{
hash.reset();
dumpIt("cS: clientPublicKey", clientPublicKey);
hash.processStrippedInt(clientPublicKey);
dumpIt("cS: serverPublicKey", serverPublicKey);
hash.processStrippedInt(serverPublicKey);
hash.getInt(scramble);
}
void RemotePassword::clientSessionKey(UCharBuffer& sessionKey, const char* account,
const char* salt, const char* password,
const char* serverPubKey)
{
serverPublicKey = BigInteger(serverPubKey);
computeScramble();
dumpIt("scramble", scramble);
BigInteger x = getUserHash(account, salt, password); // x
BigInteger gx = group->generator.modPow(x, group->prime); // g^x
BigInteger kgx = (group->k * gx) % group->prime; // kg^x
dumpIt("kgx", kgx);
BigInteger diff = (serverPublicKey - kgx) % group->prime; // B - kg^x
BigInteger ux = (scramble * x) % group->prime; // ux
BigInteger aux = (privateKey + ux) % group->prime; // A + ux
dumpIt("clientPrivateKey", privateKey);
dumpIt("aux", aux);
BigInteger sessionSecret = diff.modPow(aux, group->prime); // (B - kg^x) ^ (a + ux)
dumpIt("sessionSecret", sessionSecret);
hash.reset();
hash.processStrippedInt(sessionSecret);
hash.getHash(sessionKey);
}
void RemotePassword::serverSessionKey(UCharBuffer& sessionKey, const char* clientPubKey,
const UCharBuffer& verifier)
{
clientPublicKey = BigInteger(clientPubKey);
computeScramble();
dumpIt("scramble", scramble);
BigInteger v = BigInteger(verifier);
BigInteger vu = v.modPow(scramble, group->prime); // v^u
BigInteger Avu = (clientPublicKey * vu) % group->prime; // Av^u
dumpIt("Avu", Avu);
BigInteger sessionSecret = Avu.modPow(privateKey, group->prime); // (Av^u) ^ b
dumpIt("serverPrivateKey", privateKey);
dumpIt("sessionSecret", sessionSecret);
hash.reset();
hash.processStrippedInt(sessionSecret);
hash.getHash(sessionKey);
}
// H(H(prime) ^ H(g), H(I), s, A, B, K)
BigInteger RemotePassword::clientProof(const char* account, const char* salt, const UCharBuffer& sessionKey)
{
hash.reset();
hash.processInt(group->prime);
BigInteger n1;
hash.getInt(n1);
hash.reset();
hash.processInt(group->generator);
BigInteger n2;
hash.getInt(n2);
n1 = n1.modPow(n2, group->prime);
hash.reset();
hash.process(account);
hash.getInt(n2);
hash.reset();
hash.processInt(n1); // H(prime) ^ H(g)
hash.processInt(n2); // H(I)
hash.process(salt); // s
hash.processInt(clientPublicKey); // A
hash.processInt(serverPublicKey); // B
hash.process(sessionKey); // K
BigInteger rc;
hash.getInt(rc);
return rc;
}
#if SRP_DEBUG > 0
void dumpIt(const char* name, const Firebird::UCharBuffer& data)
{
fprintf(stderr, "%s\n", name);
for (size_t x=0; x<data.getCount(); ++x)
fprintf(stderr, "%02x ", data[x]);
fprintf(stderr, "\n");
}
void dumpIt(const char* name, const Firebird::string& str)
{
fprintf(stderr, "%s: '%s'\n", name, str.c_str());
}
void dumpIt(const char* name, const BigInteger& bi)
{
string x;
bi.getText(x);
dumpIt(name, x);
}
#endif
} // namespace Auth

View File

@ -0,0 +1,126 @@
#include "../auth/SecureRemotePassword/BigInteger.h"
#include "../common/classes/alloc.h"
#include "../common/classes/fb_string.h"
#include "../common/sha.h"
#define SRP_DEBUG 0 // >0 - prints some debug info
// >1 - uses consts instead randoms, NEVER use in PRODUCTION!
// for HANDSHAKE_DEBUG
#include "../remote/remot_proto.h"
namespace Auth {
/*
* Order of battle for SRP handshake:
*
* 0. At account creation, the server generates
* a random salt and computes a password
* verifier from the account name, password,
* and salt.
*
* 1. Client generates random number
* as private key, computes public
* key.
*
* 2. Client sends server the account
* name and its public key.
* 3. Server receives account name, looks up
* salt and password verifier. Server
* generates random number as private key.
* Server computes public key from private
* key, account name, verifier, and salt.
*
* 4. Server sends client public key and salt
*
* 3. Client receives server public
* key and computes session key
* from server key, salt, account
* name, and password.
* 5. Server computes session key from client
* public key, client name, and verifier
*
* For full details, see http://www.ietf.org/rfc/rfc5054.txt
*
*/
class RemoteGroup;
class Sha1 : public Firebird::Sha1
{
public:
void getInt(BigInteger& hash)
{
Firebird::UCharBuffer tmp;
getHash(tmp);
hash.assign(tmp.getCount(), tmp.begin());
}
void processInt(const BigInteger& data)
{
Firebird::UCharBuffer bytes;
data.getBytes(bytes);
process(bytes);
}
void processStrippedInt(const BigInteger& data)
{
Firebird::UCharBuffer bytes;
data.getBytes(bytes);
unsigned int n = (bytes[0] == 0) ? 1u : 0;
process(bytes.getCount() - n, bytes.begin() + n);
}
};
class RemotePassword : public Firebird::GlobalStorage
{
private:
const RemoteGroup* group;
Auth::Sha1 hash;
BigInteger privateKey;
BigInteger scramble;
public:
BigInteger clientPublicKey;
BigInteger serverPublicKey;
public:
RemotePassword();
static const char* plugName;
static const unsigned SRP_KEY_SIZE = 128;
static const unsigned SRP_VERIFIER_SIZE = SRP_KEY_SIZE;
static const unsigned SRP_SALT_SIZE = 32;
BigInteger getUserHash(const char* account,
const char* salt,
const char* password);
BigInteger computeVerifier(const Firebird::string& account,
const Firebird::string& salt,
const Firebird::string& password);
void genClientKey(Firebird::string& clientPubKey);
void genServerKey(Firebird::string& serverPubKey, const Firebird::UCharBuffer& verifier);
void computeScramble();
void clientSessionKey(Firebird::UCharBuffer& sessionKey, const char* account,
const char* salt, const char* password,
const char* serverPubKey);
void serverSessionKey(Firebird::UCharBuffer& sessionKey,
const char* clientPubKey,
const Firebird::UCharBuffer& verifier);
BigInteger clientProof(const char* account,
const char* salt,
const Firebird::UCharBuffer& sessionKey);
};
#if SRP_DEBUG > 0
void dumpIt(const char* name, const BigInteger& bi);
void dumpIt(const char* name, const Firebird::UCharBuffer& data);
void dumpIt(const char* name, const Firebird::string& str);
#else
void static inline dumpIt(const char* name, const BigInteger& bi) { }
void static inline dumpIt(const char* name, const Firebird::UCharBuffer& data) { }
void static inline dumpIt(const char* name, const Firebird::string& str) { }
#endif
} // namespace Auth

View File

@ -1,7 +1,7 @@
/*
* PROGRAM: Firebird authentication
* MODULE: LegacyClient.cpp
* DESCRIPTION: Performs legacy actions on DPB at client side.
* DESCRIPTION: Performs legacy actions on password at client side.
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
@ -28,26 +28,33 @@
#include "firebird.h"
#include "../jrd/ibase.h"
#include "../auth/SecurityDatabase/LegacyClient.h"
#include "../auth/SecurityDatabase/LegacyHash.h"
#include "../common/enc_proto.h"
#include "../common/classes/ImplementHelper.h"
#include "../common/classes/init.h"
namespace Auth {
Result SecurityDatabaseClient::startAuthentication(Firebird::IStatus*, const AuthTags* tags, IClumplets* dpb)
Result SecurityDatabaseClient::authenticate(Firebird::IStatus*, IClientBlock* cb)
{
return dpb->find(isc_dpb_user_name) &&
(dpb->find(isc_dpb_password) || dpb->find(isc_dpb_password_enc)) ?
AUTH_SUCCESS : AUTH_CONTINUE;
if (!(cb->getLogin() && cb->getPassword()))
{
return AUTH_CONTINUE;
}
TEXT pwt[Auth::MAX_LEGACY_PASSWORD_LENGTH + 2];
ENC_crypt(pwt, sizeof pwt, cb->getPassword(), Auth::LEGACY_PASSWORD_SALT);
cb->putData(strlen(&pwt[2]), &pwt[2]);
return AUTH_SUCCESS;
}
Result SecurityDatabaseClient::contAuthentication(Firebird::IStatus*, const unsigned char*, unsigned int)
Result SecurityDatabaseClient::getSessionKey(Firebird::IStatus*,
const unsigned char** key, unsigned int* keyLen)
{
return AUTH_FAILED;
}
void SecurityDatabaseClient::getData(const unsigned char**, unsigned short* dataSize)
{
*dataSize = 0;
*key = NULL;
*keyLen = 0;
return AUTH_CONTINUE;
}
int SecurityDatabaseClient::release()

View File

@ -27,7 +27,7 @@
#ifndef AUTH_LEGACY_CLIENT_H
#define AUTH_LEGACY_CLIENT_H
#include "../auth/AuthInterface.h"
#include "firebird/Auth.h"
#include "../common/classes/ImplementHelper.h"
namespace Auth {
@ -43,9 +43,9 @@ public:
}
// IClient implementation
Result FB_CARG startAuthentication(Firebird::IStatus* status, const AuthTags* tags, IClumplets* dpb);
Result FB_CARG contAuthentication(Firebird::IStatus* status, const unsigned char* data, unsigned int size);
void FB_CARG getData(const unsigned char** data, unsigned short* dataSize);
Result FB_CARG authenticate(Firebird::IStatus*, IClientBlock* data);
Result FB_CARG getSessionKey(Firebird::IStatus* status,
const unsigned char** key, unsigned int* keyLen);
int FB_CARG release();
};

View File

@ -29,20 +29,23 @@
#include "../common/utils_proto.h"
#include "../common/sha.h"
#include "../common/os/guid.h"
#include "../common/utils_proto.h"
namespace Auth {
const size_t MAX_PASSWORD_LENGTH = 64; // used to store passwords internally
static const char* const PASSWORD_SALT = "9z"; // for old ENC_crypt()
const size_t MAX_LEGACY_PASSWORD_LENGTH = 64; // used to store passwords internally
static const char* const LEGACY_PASSWORD_SALT = "9z"; // for old ENC_crypt()
const size_t SALT_LENGTH = 12; // measured after base64 coding
class LegacyHash
{
public:
static void hash(Firebird::string& h, const Firebird::string& userName, const TEXT* passwd)
{
Firebird::string salt;
Jrd::CryptSupport::random(salt, SALT_LENGTH);
fb_utils::random64(salt, SALT_LENGTH);
hash(h, userName, passwd, salt);
}
@ -56,7 +59,7 @@ public:
Firebird::string allData(salt);
allData += userName;
allData += passwd;
Jrd::CryptSupport::hash(h, allData);
Firebird::Sha1::hashBased64(h, allData);
h = salt + h;
}
};

View File

@ -322,7 +322,7 @@ int FB_CARG SecurityDatabaseManagement::execute(Firebird::IStatus* st, IUser* us
Firebird::MutexLockGuard guard(execLineMutex);
SCHAR encrypted1[MAX_PASSWORD_LENGTH + 2];
SCHAR encrypted1[MAX_LEGACY_PASSWORD_LENGTH + 2];
Firebird::string encrypted2;
bool found;
@ -383,7 +383,7 @@ int FB_CARG SecurityDatabaseManagement::execute(Firebird::IStatus* st, IUser* us
U.PLG$GROUP_NAME.NULL = ISC_TRUE;
if (user->password()->entered())
{
ENC_crypt(encrypted1, sizeof encrypted1, user->password()->get(), PASSWORD_SALT);
ENC_crypt(encrypted1, sizeof encrypted1, user->password()->get(), LEGACY_PASSWORD_SALT);
LegacyHash::hash(encrypted2, user->userName()->get(), &encrypted1[2]);
STR_STORE(U.PLG$PASSWD, encrypted2.c_str());
U.PLG$PASSWD.NULL = ISC_FALSE;
@ -458,7 +458,7 @@ int FB_CARG SecurityDatabaseManagement::execute(Firebird::IStatus* st, IUser* us
if (user->password()->entered())
{
ENC_crypt(encrypted1, sizeof encrypted1, user->password()->get(), PASSWORD_SALT);
ENC_crypt(encrypted1, sizeof encrypted1, user->password()->get(), LEGACY_PASSWORD_SALT);
LegacyHash::hash(encrypted2, user->userName()->get(), &encrypted1[2]);
STR_STORE(U.PLG$PASSWD, encrypted2.c_str());
U.PLG$PASSWD.NULL = ISC_FALSE;

View File

@ -28,7 +28,7 @@
#define AUTH_LEGACY_MANAGEMENT_H
#include "../common/classes/ImplementHelper.h"
#include "../auth/AuthInterface.h"
#include "firebird/Auth.h"
namespace Auth {

View File

@ -61,7 +61,7 @@ const UCHAR PWD_REQUEST[] =
blr_long, 0,
blr_long, 0,
blr_short, 0,
blr_text, BLR_WORD(Auth::MAX_PASSWORD_LENGTH + 2),
blr_text, BLR_WORD(Auth::MAX_LEGACY_PASSWORD_LENGTH + 2),
blr_message, 0, 1, 0,
blr_cstring, 129, 0,
blr_receive, 0,
@ -107,7 +107,7 @@ struct user_record
SLONG gid;
SLONG uid;
SSHORT flag;
SCHAR password[Auth::MAX_PASSWORD_LENGTH + 2];
SCHAR password[Auth::MAX_LEGACY_PASSWORD_LENGTH + 2];
};
// Transaction parameter buffer
@ -120,16 +120,6 @@ const UCHAR TPB[4] =
isc_tpb_wait
};
void getString(Auth::IClumplets* dpb, UCHAR tag, string& str)
{
if (dpb->find(tag))
{
unsigned int len;
const UCHAR* s = dpb->get(&len);
str.assign(s, len);
}
}
} // anonymous namespace
namespace Auth {
@ -137,7 +127,7 @@ namespace Auth {
class SecurityDatabase : public Firebird::RefCntIface<Firebird::ITimer, FB_TIMER_VERSION>
{
public:
Result verify(IWriter* authBlock, IClumplets* originalDpb);
Result verify(IWriter* authBlock, IServerBlock* sBlock);
static int shutdown(const int, const int, void*);
@ -247,8 +237,8 @@ bool SecurityDatabase::lookup_user(const char* user_name, char* pwd)
if (pwd)
{
strncpy(pwd, user.password, MAX_PASSWORD_LENGTH);
pwd[MAX_PASSWORD_LENGTH] = 0;
strncpy(pwd, user.password, MAX_LEGACY_PASSWORD_LENGTH);
pwd[MAX_LEGACY_PASSWORD_LENGTH] = 0;
}
}
@ -301,7 +291,7 @@ void SecurityDatabase::prepare()
* Public interface
*/
Result SecurityDatabase::verify(IWriter* authBlock, IClumplets* originalDpb)
Result SecurityDatabase::verify(IWriter* authBlock, IServerBlock* sBlock)
{
static AmCache useNative = AM_UNKNOWN;
@ -318,12 +308,16 @@ Result SecurityDatabase::verify(IWriter* authBlock, IClumplets* originalDpb)
return AUTH_CONTINUE;
}
string login, password, passwordEnc;
getString(originalDpb, isc_dpb_user_name, login);
getString(originalDpb, isc_dpb_password, password);
getString(originalDpb, isc_dpb_password_enc, passwordEnc);
string login(sBlock->getLogin());
unsigned length;
const unsigned char* data = sBlock->getData(&length);
string passwordEnc;
if (data)
{
passwordEnc.assign(data, length);
}
if (login.hasData() && (password.hasData() || passwordEnc.hasData()))
if (login.hasData() && passwordEnc.hasData())
{
login.upper();
@ -331,22 +325,15 @@ Result SecurityDatabase::verify(IWriter* authBlock, IClumplets* originalDpb)
// found there. This means that another database must be accessed, and
// that means the current context must be saved and restored.
char pw1[MAX_PASSWORD_LENGTH + 1];
char pw1[MAX_LEGACY_PASSWORD_LENGTH + 1];
if (!lookup_user(login.c_str(), pw1))
{
return AUTH_FAILED;
}
pw1[MAX_PASSWORD_LENGTH] = 0;
string storedHash(pw1, MAX_PASSWORD_LENGTH);
pw1[MAX_LEGACY_PASSWORD_LENGTH] = 0;
string storedHash(pw1, MAX_LEGACY_PASSWORD_LENGTH);
storedHash.rtrim();
if (!passwordEnc.hasData())
{
char pwt[MAX_PASSWORD_LENGTH + 2];
ENC_crypt(pwt, sizeof pwt, password.c_str(), PASSWORD_SALT);
passwordEnc.assign(&pwt[2]);
}
string newHash;
LegacyHash::hash(newHash, login, passwordEnc, storedHash);
if (newHash != storedHash)
@ -354,8 +341,8 @@ Result SecurityDatabase::verify(IWriter* authBlock, IClumplets* originalDpb)
bool legacyHash = Config::getLegacyHash();
if (legacyHash)
{
newHash.resize(MAX_PASSWORD_LENGTH + 2);
ENC_crypt(newHash.begin(), newHash.length(), passwordEnc.c_str(), PASSWORD_SALT);
newHash.resize(MAX_LEGACY_PASSWORD_LENGTH + 2);
ENC_crypt(newHash.begin(), newHash.length(), passwordEnc.c_str(), LEGACY_PASSWORD_SALT);
newHash.recalculate_length();
newHash.erase(0, 2);
legacyHash = newHash == storedHash;
@ -464,9 +451,7 @@ int SecurityDatabase::shutdown(const int, const int, void*)
const static unsigned int INIT_KEY = ((~0) - 1);
static unsigned int secDbKey = INIT_KEY;
Result SecurityDatabaseServer::startAuthentication(Firebird::IStatus* status,
const AuthTags* tags, IClumplets* dpb,
IWriter* writerInterface)
Result SecurityDatabaseServer::authenticate(Firebird::IStatus* status, IServerBlock* sBlock, IWriter* writerInterface)
{
status->init();
@ -515,7 +500,7 @@ Result SecurityDatabaseServer::startAuthentication(Firebird::IStatus* status,
fb_assert(instance);
Result rc = instance->verify(writerInterface, dpb);
Result rc = instance->verify(writerInterface, sBlock);
TimerInterfacePtr()->start(instance, 10 * 1000 * 1000);
return rc;
}
@ -526,17 +511,12 @@ Result SecurityDatabaseServer::startAuthentication(Firebird::IStatus* status,
}
}
Result SecurityDatabaseServer::contAuthentication(Firebird::IStatus* status,
const unsigned char* /*data*/, unsigned int /*size*/,
IWriter* /*writerInterface*/)
Result SecurityDatabaseServer::getSessionKey(Firebird::IStatus*,
const unsigned char** key, unsigned int* keyLen)
{
return AUTH_FAILED;
}
void SecurityDatabaseServer::getData(const unsigned char** data, unsigned short* dataSize)
{
*data = NULL;
*dataSize = 0;
*key = NULL;
*keyLen = 0;
return AUTH_CONTINUE;
}
int SecurityDatabaseServer::release()

View File

@ -34,7 +34,7 @@
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/ImplementHelper.h"
#include "../auth/AuthInterface.h"
#include "firebird/Auth.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@ -51,11 +51,9 @@ public:
{ }
// IServer implementation
Result FB_CARG startAuthentication(Firebird::IStatus* status, const AuthTags* tags, IClumplets* dpb,
IWriter* writerInterface);
Result FB_CARG contAuthentication(Firebird::IStatus* status, const unsigned char* data,
unsigned int size, IWriter* writerInterface);
void FB_CARG getData(const unsigned char** data, unsigned short* dataSize);
Result FB_CARG authenticate(Firebird::IStatus* status, IServerBlock* sBlock, IWriter* writerInterface);
Result FB_CARG getSessionKey(Firebird::IStatus* status,
const unsigned char** key, unsigned int* keyLen);
int FB_CARG release();
private:

View File

@ -437,7 +437,9 @@ int WinSspiServer::release()
Result WinSspiClient::startAuthentication(Firebird::IStatus* status,
const AuthTags* tags,
IClumplets* dpb)
IClumplets* dpb,
const char* user,
const char* pass)
{
sspi.request(sspiData);

View File

@ -36,7 +36,7 @@
#include <../common/classes/array.h>
#include "../common/classes/ImplementHelper.h"
#include <../jrd/ibase.h>
#include "../auth/AuthInterface.h"
#include "firebird/Auth.h"
#define SECURITY_WIN32
@ -119,7 +119,7 @@ class WinSspiClient : public Firebird::StdPlugin<IClient, FB_AUTH_CLIENT_VERSION
public:
// IClient implementation
Result FB_CARG startAuthentication(Firebird::IStatus* status, const AuthTags* tags,
IClumplets* dpb);
IClumplets* dpb, const char* user, const char* pass);
Result FB_CARG contAuthentication(Firebird::IStatus* status,
const unsigned char* data, unsigned int size);
void FB_CARG getData(const unsigned char** data, unsigned short* dataSize);

View File

@ -96,50 +96,4 @@ void WriterImplementation::setAttribute(unsigned char tag, const char* value)
}
}
DpbImplementation::DpbImplementation(ClumpletWriter& base)
: body(&base)
{ }
int DpbImplementation::find(UCHAR tag)
{
return body->find(tag) ? 1 : 0;
}
void DpbImplementation::add(UCHAR tag, const void* bytes, unsigned int count)
{
body->insertBytes(tag, bytes, count);
}
void DpbImplementation::drop()
{
if (!body->isEof())
{
body->deleteClumplet();
}
}
const unsigned char* DpbImplementation::get(unsigned int* cntPtr)
{
if (body->isEof())
{
return NULL;
}
if (cntPtr)
{
*cntPtr = body->getClumpLength();
}
return body->getBytes();
}
bool legacy(const char* nm)
{
const char* legacyTrusted = "WIN_SSPI";
return fb_utils::stricmp(legacyTrusted, nm) == 0;
}
} // namespace Auth

View File

@ -30,7 +30,7 @@
#ifndef FB_AUTH_H
#define FB_AUTH_H
#include "../auth/AuthInterface.h"
#include "firebird/Auth.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/init.h"
#include "../common/classes/array.h"
@ -39,8 +39,6 @@
namespace Auth {
bool legacy(const char* nm);
class WriterImplementation : public Firebird::AutoIface<IWriter, FB_AUTH_WRITER_VERSION>
{
public:
@ -62,26 +60,6 @@ private:
void putLevel();
};
class DpbImplementation : public Firebird::AutoIface<IClumplets, FB_AUTH_CLUMPLETS_VERSION>
{
public:
DpbImplementation(Firebird::ClumpletWriter& base);
// DpbImplementation implementation
int FB_CARG find(UCHAR tag);
void FB_CARG add(UCHAR tag, const void* bytes, unsigned int count);
void FB_CARG drop();
const unsigned char* FB_CARG get(unsigned int* cntPtr);
private:
Firebird::ClumpletWriter* body;
};
static const AuthTags DB_ATTACH_LIST = {isc_dpb_auth_block, isc_dpb_trusted_auth, isc_dpb_trusted_role, 0};
static const AuthTags SVC_ATTACH_LIST = {isc_spb_auth_block, isc_spb_trusted_auth, isc_spb_trusted_role, 1};
static const AuthTags SVC_START_LIST = {isc_spb_auth_block, isc_spb_trusted_auth, 0, 1};
static const AuthTags SVC_QUERY_LIST = {isc_info_svc_auth_block, 0, 0, 1};
} // namespace Auth

View File

@ -128,6 +128,13 @@ ClumpletReader::ClumpletReader(MemoryPool& pool, const ClumpletReader& from) :
rewind(); // this will set cur_offset and spbState
}
ClumpletReader::ClumpletReader(const ClumpletReader& from) :
AutoStorage(), kind(from.kind),
static_buffer(from.getBuffer()), static_buffer_end(from.getBufferEnd())
{
rewind(); // this will set cur_offset and spbState
}
ClumpletReader::ClumpletReader(MemoryPool& pool, const KindList* kl,
const UCHAR* buffer, size_t buffLen, FPTR_VOID raise) :
AutoStorage(pool), kind(kl->kind), static_buffer(buffer), static_buffer_end(buffer + buffLen)
@ -253,6 +260,9 @@ UCHAR ClumpletReader::getBufferTag() const
return 0;
}
return buffer_start[1];
case isc_spb_version3:
// This is wide SPB attach format - buffer's tag is the first byte.
return buffer_start[0];
default:
invalid_structure("spb in service attach should begin with isc_spb_version1 or isc_spb_version");
return 0;
@ -300,8 +310,12 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const
case SpbReceiveItems:
return SingleTpb;
case SpbStart:
if (tag == isc_spb_auth_block || tag == isc_spb_trusted_auth)
switch(tag)
{
case isc_spb_auth_block:
case isc_spb_trusted_auth:
case isc_spb_auth_plugin_name:
case isc_spb_auth_plugin_list:
return Wide;
}
switch (spbState)
@ -609,6 +623,27 @@ bool ClumpletReader::find(UCHAR tag)
return false;
}
bool ClumpletReader::next(UCHAR tag)
{
if (!isEof())
{
const size_t co = getCurOffset();
if (tag == getClumpTag())
{
moveNext();
}
for (; !isEof(); moveNext())
{
if (tag == getClumpTag())
{
return true;
}
}
setCurOffset(co);
}
return false;
}
// Methods which work with currently selected clumplet
UCHAR ClumpletReader::getClumpTag() const
{
@ -746,6 +781,11 @@ PathName& ClumpletReader::getPath(PathName& str) const
return str;
}
void ClumpletReader::getData(UCharBuffer& data) const
{
data.assign(getBytes(), getClumpLength());
}
bool ClumpletReader::getBoolean() const
{
const UCHAR* ptr = getBytes();

View File

@ -83,12 +83,14 @@ public:
// Create a copy of reader
ClumpletReader(MemoryPool& pool, const ClumpletReader& from);
ClumpletReader(const ClumpletReader& from);
// Navigation in clumplet buffer
bool isEof() const { return cur_offset >= getBufferLength(); }
void moveNext();
void rewind();
bool find(UCHAR tag);
bool next(UCHAR tag);
// Methods which work with currently selected clumplet
UCHAR getClumpTag() const;
@ -99,6 +101,7 @@ public:
SINT64 getBigInt() const;
string& getString(string& str) const;
PathName& getPath(PathName& str) const;
void getData(UCharBuffer& data) const;
const UCHAR* getBytes() const;
double getDouble() const;
ISC_TIMESTAMP getTimeStamp() const;
@ -164,8 +167,7 @@ protected:
virtual void invalid_structure(const char* what) const;
private:
// Assignment and copy constructor not implemented.
ClumpletReader(const ClumpletReader& from);
// Assignment not implemented.
ClumpletReader& operator=(const ClumpletReader& from);
const UCHAR* static_buffer;
@ -175,8 +177,9 @@ private:
void create(const KindList* kl, size_t buffLen, FPTR_VOID raise);
public:
static const KindList dpbList[]; // Some frequently used kind lists
static const KindList spbList[]; // Some frequently used kind lists
// Some frequently used kind lists
static const KindList dpbList[];
static const KindList spbList[];
};
class AuthReader : public ClumpletReader

View File

@ -120,6 +120,12 @@ ClumpletWriter::ClumpletWriter(MemoryPool& pool, const ClumpletWriter& from)
create(from.getBuffer(), from.getBufferEnd() - from.getBuffer(), from.isTagged() ? from.getBufferTag() : 0);
}
ClumpletWriter::ClumpletWriter(const ClumpletWriter& from)
: ClumpletReader(from), sizeLimit(from.sizeLimit), kindList(NULL), dynamic_buffer(getPool())
{
create(from.getBuffer(), from.getBufferEnd() - from.getBuffer(), from.isTagged() ? from.getBufferTag() : 0);
}
void ClumpletWriter::create(const UCHAR* buffer, size_t buffLen, UCHAR tag)
{
if (buffer && buffLen) {

View File

@ -62,6 +62,7 @@ public:
// Create a copy of writer
ClumpletWriter(MemoryPool& pool, const ClumpletWriter& from);
ClumpletWriter(const ClumpletWriter& from);
void reset(UCHAR tag);
void reset(const UCHAR* buffer, const size_t buffLen);
@ -99,8 +100,7 @@ protected:
bool upgradeVersion(); // upgrade clumplet version - obtain newest from kindList
private:
// Assignment and copy constructor not implemented.
ClumpletWriter(const ClumpletWriter& from);
// Assignment not implemented.
ClumpletWriter& operator=(const ClumpletWriter& from);
size_t sizeLimit;

View File

@ -31,6 +31,7 @@
#include "../common/classes/ImplementHelper.h"
#include "../common/config/config.h"
#include "../common/StatusHolder.h"
namespace Firebird {
@ -42,11 +43,18 @@ public:
GetPlugins(unsigned int interfaceType, unsigned int desiredVersion,
UpgradeInfo* ui, const char* namesList = NULL)
: masterInterface(), pluginInterface(masterInterface),
pluginSet(pluginInterface->getPlugins(interfaceType,
namesList ? namesList : Config::getPlugins(interfaceType),
desiredVersion, ui, NULL)),
currentPlugin(NULL)
pluginSet(NULL), currentPlugin(NULL)
{
LocalStatus status;
pluginSet = pluginInterface->getPlugins(&status, interfaceType,
namesList ? namesList : Config::getPlugins(interfaceType),
desiredVersion, ui, NULL);
if (!pluginSet)
{
fb_assert(!status.isSuccess());
status_exception::raise(status.get());
}
pluginSet->release();
getPlugin();
}
@ -54,11 +62,18 @@ public:
GetPlugins(unsigned int interfaceType, unsigned int desiredVersion, UpgradeInfo* ui,
Config* knownConfig, const char* namesList = NULL)
: masterInterface(), pluginInterface(masterInterface),
pluginSet(pluginInterface->getPlugins(interfaceType,
namesList ? namesList : Config::getPlugins(interfaceType),
desiredVersion, ui, new FirebirdConf(knownConfig))),
currentPlugin(NULL)
pluginSet(NULL), currentPlugin(NULL)
{
LocalStatus status;
pluginSet = pluginInterface->getPlugins(&status, interfaceType,
namesList ? namesList : Config::getPlugins(interfaceType),
desiredVersion, ui, new FirebirdConf(knownConfig));
if (!pluginSet)
{
fb_assert(!status.isSuccess());
status_exception::raise(status.get());
}
pluginSet->release();
getPlugin();
}

View File

@ -31,6 +31,7 @@
#include <string.h>
#include "../common/classes/vector.h"
#include "../common/classes/alloc.h"
#include "../common/common.h"
namespace Firebird {
@ -312,6 +313,12 @@ public:
copyFrom(source);
}
void assign(const T* items, const size_t itemsCount)
{
resize(itemsCount);
memcpy(data, items, sizeof(T) * count);
}
// NOTE: getCount method must be signal safe
// Used as such in GlobalRWLock::blockingAstHandler
size_t getCount() const { return count; }
@ -334,6 +341,16 @@ public:
count += itemsSize;
}
void append(const T* items, const size_t itemsSize)
{
push(items, itemsSize);
}
void append(const Array<T, Storage>& source)
{
push(source.begin(), source.getCount());
}
T pop()
{
fb_assert(count > 0);
@ -477,7 +494,7 @@ public:
Array<T, InlineStorage<T, InlineCapacity> > (InitialCapacity) {}
};
typedef HalfStaticArray<UCHAR, 16> UCharBuffer;
typedef HalfStaticArray<UCHAR, BUFFER_TINY> UCharBuffer;
} // namespace Firebird

View File

@ -867,9 +867,9 @@ void GDS_breakpoint(int);
#define STRINGIZE(x) STRINGIZE_AUX(x)
#ifdef _MSC_VER
#define CONST64(a) (a##i64)
#define FB_CONST64(a) (a##i64)
#else
#define CONST64(a) (a##LL)
#define FB_CONST64(a) (a##LL)
#endif
// 30 Dec 2002. Nickolay Samofatov

View File

@ -164,9 +164,9 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{TYPE_INTEGER, "MaxUserTraceLogSize", (ConfigValue) 10}, // maximum size of user session trace log
{TYPE_INTEGER, "FileSystemCacheSize", (ConfigValue) 30}, // percent
{TYPE_STRING, "Providers", (ConfigValue) "Remote, Engine12, Loopback"},
{TYPE_STRING, "AuthServer", (ConfigValue) "Legacy_Auth, Win_Sspi"},
{TYPE_STRING, "AuthClient", (ConfigValue) "Legacy_Auth, Win_Sspi"},
{TYPE_STRING, "UserManager", (ConfigValue) "Legacy_UserManager"},
{TYPE_STRING, "AuthServer", (ConfigValue) "Srp, Win_Sspi"},
{TYPE_STRING, "AuthClient", (ConfigValue) "Srp, Win_Sspi, Legacy_Auth"},
{TYPE_STRING, "UserManager", (ConfigValue) "Srp"},
{TYPE_STRING, "TracePlugin", (ConfigValue) "fbtrace"},
{TYPE_STRING, "SecurityDatabase", (ConfigValue) "$(root)/security3.fdb"}, // security database name
{TYPE_BOOLEAN, "SharedCache", (ConfigValue) true},

View File

@ -24,7 +24,7 @@
#ifndef UTILITIES_SECUR_PROTO_H
#define UTILITIES_SECUR_PROTO_H
#include "../auth/AuthInterface.h"
#include "firebird/Auth.h"
#include "../common/classes/ImplementHelper.h"
#include "../common/classes/GetPlugins.h"
#include "../common/classes/array.h"

View File

@ -14,27 +14,19 @@
#include "../common/sha.h"
#include "../common/classes/array.h"
#include "../common/os/guid.h"
#include "../common/utils_proto.h"
using namespace Firebird;
namespace
{
// Useful defines & typedefs
typedef unsigned char BYTE; // 8-bit quantity
typedef unsigned long LONG; // 32-or-more-bit quantity
#define SHA_BLOCKSIZE 64
#define SHA_DIGESTSIZE 20
struct SHA_INFO
{
LONG digest[5]; // message digest
LONG count_lo, count_hi; // 64-bit bit count
BYTE data[SHA_BLOCKSIZE]; // SHA data buffer
int local; // unprocessed amount in data
};
#define SHA_BLOCKSIZE Sha1::BLOCK_SIZE
#define SHA_DIGESTSIZE Sha1::HASH_SIZE
typedef Sha1::ShaInfo SHA_INFO;
void sha_init(SHA_INFO *);
void sha_update(SHA_INFO *, const BYTE *, int);
void sha_update(SHA_INFO *, const BYTE *, unsigned int);
void sha_final(unsigned char [SHA_DIGESTSIZE], SHA_INFO *);
#define SHA_VERSION 1
@ -135,7 +127,7 @@ void sha_final(unsigned char [SHA_DIGESTSIZE], SHA_INFO *);
static void sha_transform(SHA_INFO *sha_info)
{
int i;
LONG W[80];
Sha1::LONG W[80];
const BYTE* dp = sha_info->data;
@ -151,7 +143,7 @@ nether regions of the anatomy...
#define SWAP_DONE
for (i = 0; i < 16; ++i)
{
const LONG T = *((LONG *) dp);
const Sha1::LONG T = *((Sha1::LONG *) dp);
dp += 4;
W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
@ -162,7 +154,7 @@ nether regions of the anatomy...
#define SWAP_DONE
for (i = 0; i < 16; ++i)
{
const LONG T = *((LONG *) dp);
const Sha1::LONG T = *((Sha1::LONG *) dp);
dp += 4;
W[i] = T32(T);
}
@ -172,7 +164,7 @@ nether regions of the anatomy...
#define SWAP_DONE
for (i = 0; i < 16; i += 2)
{
LONG T = *((LONG *) dp);
Sha1::LONG T = *((Sha1::LONG *) dp);
dp += 8;
W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
@ -186,7 +178,7 @@ nether regions of the anatomy...
#define SWAP_DONE
for (i = 0; i < 16; i += 2)
{
const LONG T = *((LONG *) dp);
const Sha1::LONG T = *((Sha1::LONG *) dp);
dp += 8;
W[i] = T32(T >> 32);
W[i + 1] = T32(T);
@ -204,13 +196,13 @@ nether regions of the anatomy...
W[i] = R32(W[i], 1);
#endif // SHA_VERSION
}
LONG A = sha_info->digest[0];
LONG B = sha_info->digest[1];
LONG C = sha_info->digest[2];
LONG D = sha_info->digest[3];
LONG E = sha_info->digest[4];
const LONG* WP = W;
LONG T;
Sha1::LONG A = sha_info->digest[0];
Sha1::LONG B = sha_info->digest[1];
Sha1::LONG C = sha_info->digest[2];
Sha1::LONG D = sha_info->digest[3];
Sha1::LONG E = sha_info->digest[4];
const Sha1::LONG* WP = W;
Sha1::LONG T;
#ifdef UNRAVEL
FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1);
FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1);
@ -265,17 +257,17 @@ void sha_init(SHA_INFO *sha_info)
// update the SHA digest
void sha_update(SHA_INFO *sha_info, const BYTE *buffer, int count)
void sha_update(SHA_INFO *sha_info, const BYTE *buffer, unsigned int count)
{
const LONG clo = T32(sha_info->count_lo + ((LONG) count << 3));
const Sha1::LONG clo = T32(sha_info->count_lo + ((Sha1::LONG) count << 3));
if (clo < sha_info->count_lo) {
++sha_info->count_hi;
}
sha_info->count_lo = clo;
sha_info->count_hi += (LONG) count >> 29;
sha_info->count_hi += (Sha1::LONG) count >> 29;
if (sha_info->local)
{
int i = SHA_BLOCKSIZE - sha_info->local;
unsigned int i = SHA_BLOCKSIZE - sha_info->local;
if (i > count) {
i = count;
}
@ -305,9 +297,9 @@ void sha_update(SHA_INFO *sha_info, const BYTE *buffer, int count)
void sha_final(unsigned char digest[SHA_DIGESTSIZE], SHA_INFO *sha_info)
{
const LONG lo_bit_count = sha_info->count_lo;
const LONG hi_bit_count = sha_info->count_hi;
int count = (int) ((lo_bit_count >> 3) & 0x3f);
const Sha1::LONG lo_bit_count = sha_info->count_lo;
const Sha1::LONG hi_bit_count = sha_info->count_hi;
unsigned int count = (int) ((lo_bit_count >> 3) & 0x3f);
sha_info->data[count++] = 0x80;
if (count > SHA_BLOCKSIZE - 8)
{
@ -349,57 +341,58 @@ void sha_final(unsigned char digest[SHA_DIGESTSIZE], SHA_INFO *sha_info)
digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff);
}
inline char conv_bin2ascii(ULONG l)
{
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[l & 0x3f];
}
} // anonymous namespace
typedef Firebird::HalfStaticArray<unsigned char, SHA_DIGESTSIZE> BinHash;
namespace Firebird {
void base64(Firebird::string& b64, const BinHash& bin)
{
b64.erase();
const unsigned char* f = bin.begin();
for (int i = bin.getCount(); i > 0; i -= 3, f += 3)
void Sha1::hashBased64(Firebird::string& hash, const Firebird::string& data)
{
if (i >= 3)
SHA_INFO si;
sha_init(&si);
sha_update(&si, reinterpret_cast<const unsigned char*>(data.c_str()), data.length());
UCharBuffer b;
sha_final(b.getBuffer(SHA_DIGESTSIZE), &si);
fb_utils::base64(hash, b);
}
Sha1::Sha1()
: active(false)
{
reset();
}
void Sha1::process(unsigned int length, const void* bytes)
{
sha_update(&handle, reinterpret_cast<const unsigned char*>(bytes), length);
}
void Sha1::getHash(UCharBuffer& hash)
{
fb_assert(active);
sha_final(hash.getBuffer(HASH_SIZE), &handle);
}
void Sha1::reset()
{
clear();
sha_init(&handle);
active = true;
}
Sha1::~Sha1()
{
clear();
}
void Sha1::clear()
{
if (active)
{
const ULONG l = (ULONG(f[0]) << 16) | (ULONG(f[1]) << 8) | f[2];
b64 += conv_bin2ascii(l >> 18);
b64 += conv_bin2ascii(l >> 12);
b64 += conv_bin2ascii(l >> 6);
b64 += conv_bin2ascii(l);
}
else
{
ULONG l = ULONG(f[0]) << 16;
if (i == 2)
l |= (ULONG(f[1]) << 8);
b64 += conv_bin2ascii(l >> 18);
b64 += conv_bin2ascii(l >> 12);
b64 += (i == 1 ? '=' : conv_bin2ascii(l >> 6));
b64 += '=';
unsigned char tmp[HASH_SIZE];
sha_final(tmp, &handle);
active = false;
}
}
}
} // anon namespace
void Jrd::CryptSupport::hash(Firebird::string& hashValue, const Firebird::string& data)
{
SHA_INFO si;
sha_init(&si);
sha_update(&si, reinterpret_cast<const unsigned char*>(data.c_str()), data.length());
BinHash bh;
sha_final(bh.getBuffer(SHA_DIGESTSIZE), &si);
base64(hashValue, bh);
}
void Jrd::CryptSupport::random(Firebird::string& randomValue, size_t length)
{
BinHash binRand;
Firebird::GenerateRandomBytes(binRand.getBuffer(length), length);
base64(randomValue, binRand);
randomValue.resize(length, '$');
}
} // namespace Firebird

View File

@ -20,24 +20,64 @@
* Contributor(s): ______________________________________.
*/
#ifndef JRD_OS_SHA_H
#define JRD_OS_SHA_H
#ifndef COMMON_SHA_H
#define COMMON_SHA_H
#include "firebird.h"
#include "../common/classes/alloc.h"
#include "../common/classes/array.h"
#include "../common/classes/fb_string.h"
namespace Jrd
{
class CryptSupport
{
private:
CryptSupport() {}
~CryptSupport() {}
public:
// hash and random return base64-coded values
static void hash(Firebird::string& hashValue, const Firebird::string& data);
static void random(Firebird::string& randomValue, size_t length);
};
}
namespace Firebird {
#endif //JRD_OS_SHA_H
class Sha1 : public GlobalStorage
{
public:
Sha1();
static const unsigned int HASH_SIZE = 20;
static const unsigned int BLOCK_SIZE = 64;
typedef unsigned long LONG;
struct ShaInfo
{
LONG digest[5]; // message digest
LONG count_lo, count_hi; // 64-bit bit count
UCHAR data[BLOCK_SIZE]; // SHA data buffer
unsigned int local; // unprocessed amount in data
};
void process(unsigned int length, const void* bytes);
void process(const UCharBuffer& bytes)
{
process(bytes.getCount(), bytes.begin());
}
void process(const string& str)
{
process(str.length(), str.c_str());
}
void process(const char* str)
{
process(strlen(str), str);
}
void getHash(UCharBuffer& h);
void reset();
~Sha1();
// return base64-coded values
static void hashBased64(Firebird::string& hashBase64, const Firebird::string& data);
private:
void clear();
ShaInfo handle;
bool active;
};
} // namespace Firebird
#endif // COMMON_SHA_H

View File

@ -254,7 +254,7 @@ void ThreadCleanup::remove(FPTR_VOID_PTR cleanup, void* arg)
delete toDelete;
}
#else // USE_POSIX_THREADS
#else // USE_THREAD_DESTRUCTOR
ThreadCleanup** ThreadCleanup::findCleanup(FPTR_VOID_PTR, void*)
{
@ -273,4 +273,4 @@ void ThreadCleanup::remove(FPTR_VOID_PTR, void*)
{
}
#endif // USE_POSIX_THREADS
#endif // USE_THREAD_DESTRUCTOR

View File

@ -28,6 +28,7 @@
#include "firebird.h"
#include "../common/common.h"
#include "../common/os/guid.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@ -1084,6 +1085,7 @@ unsigned int statusLength(const ISC_STATUS* const status) throw()
}
}
// moves DB path information (from limbo transaction) to another buffer
void getDbPathInfo(unsigned int& itemsLength, const unsigned char*& items,
unsigned int& bufferLength, unsigned char*& buffer,
Firebird::Array<unsigned char>& newItemsBuffer, const Firebird::PathName& dbpath)
@ -1178,4 +1180,45 @@ bool isRunningCheck(const UCHAR* items, unsigned int length)
return state == S_RUN;
}
static inline char conv_bin2ascii(ULONG l)
{
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[l & 0x3f];
}
// converts bytes to BASE64 representation
void base64(Firebird::string& b64, const Firebird::UCharBuffer& bin)
{
b64.erase();
const unsigned char* f = bin.begin();
for (int i = bin.getCount(); i > 0; i -= 3, f += 3)
{
if (i >= 3)
{
const ULONG l = (ULONG(f[0]) << 16) | (ULONG(f[1]) << 8) | f[2];
b64 += conv_bin2ascii(l >> 18);
b64 += conv_bin2ascii(l >> 12);
b64 += conv_bin2ascii(l >> 6);
b64 += conv_bin2ascii(l);
}
else
{
ULONG l = ULONG(f[0]) << 16;
if (i == 2)
l |= (ULONG(f[1]) << 8);
b64 += conv_bin2ascii(l >> 18);
b64 += conv_bin2ascii(l >> 12);
b64 += (i == 1 ? '=' : conv_bin2ascii(l >> 6));
b64 += '=';
}
}
}
void random64(Firebird::string& randomValue, size_t length)
{
Firebird::UCharBuffer binRand;
Firebird::GenerateRandomBytes(binRand.getBuffer(length), length);
base64(randomValue, binRand);
randomValue.resize(length, '$');
}
} // namespace fb_utils

View File

@ -152,12 +152,20 @@ namespace fb_utils
// Add appropriate file prefix.
Firebird::PathName getPrefix(FB_DIR prefType, const char* name);
// moves DB path information (from limbo transaction) to another buffer
void getDbPathInfo(unsigned int& itemsLength, const unsigned char*& items,
unsigned int& bufferLength, unsigned char*& buffer,
Firebird::Array<unsigned char>& newItemsBuffer, const Firebird::PathName& dbpath);
// returns true if passed info items work with running svc thread
bool isRunningCheck(const UCHAR* items, unsigned int length);
// converts bytes to BASE64 representation
void base64(Firebird::string& b64, const Firebird::UCharBuffer& bin);
// generate random string in BASE64 representation
void random64(Firebird::string& randomValue, size_t length);
} // namespace fb_utils
#endif // INCLUDE_UTILS_PROTO_H

View File

@ -112,6 +112,10 @@
#define isc_dpb_utf8_filename 77
#define isc_dpb_ext_call_depth 78
#define isc_dpb_auth_block 79
// This 3 will not be used in protocol 13, therefore may be reused
#define isc_dpb_specific_auth_data isc_dpb_trusted_auth
#define isc_dpb_auth_plugin_list isc_dpb_password
#define isc_dpb_auth_plugin_name isc_dpb_password_enc
/**************************************************/
/* clumplet tags used inside isc_dpb_address_path */
@ -266,12 +270,16 @@
#define isc_spb_trusted_role 113
#define isc_spb_verbint 114
#define isc_spb_auth_block 115
#define isc_spb_auth_plugin_name 116
#define isc_spb_auth_plugin_list 117
#define isc_spb_connect_timeout isc_dpb_connect_timeout
#define isc_spb_dummy_packet_interval isc_dpb_dummy_packet_interval
#define isc_spb_sql_role_name isc_dpb_sql_role_name
// This will not be used in protocol 13, therefore may be reused
#define isc_spb_specific_auth_data isc_spb_trusted_auth
/*****************************
* Service action items *
*****************************/

View File

@ -1,6 +1,6 @@
/*
* PROGRAM: Firebird authentication
* MODULE: AuthInterface.h
* MODULE: Auth.h
* DESCRIPTION: Interfaces, used by authentication plugins
*
* The contents of this file are subject to the Initial
@ -48,42 +48,46 @@ public:
};
#define FB_AUTH_WRITER_VERSION (FB_VERSIONED_VERSION + 3)
class IClumplets : public Firebird::IVersioned
// Representation of auth-related data, passed to server auth plugin
class IServerBlock : public Firebird::IRefCounted
{
public:
virtual int FB_CARG find(UCHAR tag) = 0;
virtual void FB_CARG add(UCHAR tag, const void* bytes, unsigned int count) = 0;
virtual void FB_CARG drop() = 0;
virtual const unsigned char* FB_CARG get(unsigned int* cntPtr) = 0;
virtual const char* FB_CARG getLogin() = 0;
virtual const unsigned char* FB_CARG getData(unsigned int* length) = 0;
virtual void FB_CARG putData(unsigned int length, const void* data) = 0;
};
#define FB_AUTH_CLUMPLETS_VERSION (FB_VERSIONED_VERSION + 4)
#define FB_AUTH_SERVER_BLOCK_VERSION (FB_VERSIONED_VERSION + 3)
// This struct defines auth-related tags (including legacy ones) in parameter blocks
struct AuthTags
// Representation of auth-related data, passed to client auth plugin
class IClientBlock : public Firebird::IRefCounted
{
UCHAR authBlock, trustedAuth, trustedRole;
UCHAR service; // non-zero if we work with service connection
public:
virtual const char* FB_CARG getLogin() = 0;
virtual const char* FB_CARG getPassword() = 0;
virtual const unsigned char* FB_CARG getData(unsigned int* length) = 0;
virtual void FB_CARG putData(unsigned int length, const void* data) = 0;
};
#define FB_AUTH_CLIENT_BLOCK_VERSION (FB_VERSIONED_VERSION + 4)
// server part of authentication plugin
class IServer : public Firebird::IPluginBase
{
public:
virtual Result FB_CARG startAuthentication(Firebird::IStatus* status, const AuthTags* tags, IClumplets* dpb,
IWriter* writerInterface) = 0;
virtual Result FB_CARG contAuthentication(Firebird::IStatus* status, const unsigned char* data,
unsigned int size, IWriter* writerInterface) = 0;
virtual void FB_CARG getData(const unsigned char** data, unsigned short* dataSize) = 0;
virtual Result FB_CARG authenticate(Firebird::IStatus* status, IServerBlock* sBlock, IWriter* writerInterface) = 0;
virtual Result FB_CARG getSessionKey(Firebird::IStatus* status,
const unsigned char** key, unsigned int* keyLen) = 0;
};
#define FB_AUTH_SERVER_VERSION (FB_PLUGIN_VERSION + 3)
#define FB_AUTH_SERVER_VERSION (FB_PLUGIN_VERSION + 2)
// .. and corresponding client
class IClient : public Firebird::IPluginBase
{
public:
virtual Result FB_CARG startAuthentication(Firebird::IStatus* status, const AuthTags* tags, IClumplets* dpb) = 0;
virtual Result FB_CARG contAuthentication(Firebird::IStatus* status, const unsigned char* data, unsigned int size) = 0;
virtual void FB_CARG getData(const unsigned char** data, unsigned short* dataSize) = 0;
virtual Result FB_CARG authenticate(Firebird::IStatus* status, IClientBlock* cBlock) = 0;
virtual Result FB_CARG getSessionKey(Firebird::IStatus* status,
const unsigned char** key, unsigned int* keyLen) = 0;
};
#define FB_AUTH_CLIENT_VERSION (FB_PLUGIN_VERSION + 3)
#define FB_AUTH_CLIENT_VERSION (FB_PLUGIN_VERSION + 2)
class IUserField : public Firebird::IVersioned
{

View File

@ -186,9 +186,9 @@ public:
// in case when plugin's version is less than desired
// If caller already has an interface for firebird.conf, it may be passed here
// If parameter is missing, plugins will get access to default (non database specific) config
virtual IPluginSet* FB_CARG getPlugins(unsigned int interfaceType, const char* namesList,
int desiredVersion, UpgradeInfo* ui,
IFirebirdConf* firebirdConf) = 0;
virtual IPluginSet* FB_CARG getPlugins(IStatus* status, unsigned int interfaceType,
const char* namesList, int desiredVersion,
UpgradeInfo* ui, IFirebirdConf* firebirdConf) = 0;
// Get generic config interface for given file
virtual IConfig* FB_CARG getConfig(const char* filename) = 0;
// Plugins must be released using this function - use of plugin's release()
@ -210,10 +210,19 @@ namespace PluginType {
static const unsigned int AuthUserManagement = 13;
static const unsigned int ExternalEngine = 14;
static const unsigned int Trace = 15;
static const unsigned int Crypt = 15;
static const unsigned int MaxType = 16; // keep in sync please
};
class ICrypt : public IPluginBase
{
public:
virtual void FB_CARG setKey(IStatus* status, unsigned int length, const void* key) = 0;
virtual void FB_CARG transform(IStatus* status, unsigned int length, void* to, const void* from) = 0;
};
#define FB_CRYPT_VERSION (FB_PLUGIN_VERSION + 1)
} // namespace Firebird

View File

@ -115,6 +115,7 @@ class IStatement : public IRefCounted
{
public:
// Prepare flags.
static const unsigned PREPARE_PREFETCH_NONE = 0x0;
static const unsigned PREPARE_PREFETCH_TYPE = 0x01;
static const unsigned PREPARE_PREFETCH_INPUT_PARAMETERS = 0x02;
static const unsigned PREPARE_PREFETCH_OUTPUT_PARAMETERS = 0x04;

View File

@ -730,6 +730,7 @@ static const struct {
{"ee_blr_mismatch_null", 335545026},
{"ee_blr_mismatch_length", 335545027},
{"ss_out_of_bounds", 335545028},
{"missing_data_structures", 335545029},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -764,6 +764,7 @@ const ISC_STATUS isc_spb_no_id = 335545025L;
const ISC_STATUS isc_ee_blr_mismatch_null = 335545026L;
const ISC_STATUS isc_ee_blr_mismatch_length = 335545027L;
const ISC_STATUS isc_ss_out_of_bounds = 335545028L;
const ISC_STATUS isc_missing_data_structures = 335545029L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1202,7 +1203,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
const ISC_STATUS isc_err_max = 1146;
const ISC_STATUS isc_err_max = 1147;
#else /* c definitions */
@ -1936,6 +1937,7 @@ const ISC_STATUS isc_err_max = 1146;
#define isc_ee_blr_mismatch_null 335545026L
#define isc_ee_blr_mismatch_length 335545027L
#define isc_ss_out_of_bounds 335545028L
#define isc_missing_data_structures 335545029L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2374,7 +2376,7 @@ const ISC_STATUS isc_err_max = 1146;
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1146
#define isc_err_max 1147
#endif

View File

@ -733,6 +733,7 @@ Data source : @4"}, /* eds_statement */
{335545026, "External BLR message mismatch: invalid null descriptor at field @1"}, /* ee_blr_mismatch_null */
{335545027, "External BLR message mismatch: length = @1, expected @2"}, /* ee_blr_mismatch_length */
{335545028, "Subscript @1 out of bounds [@2, @3]"}, /* ss_out_of_bounds */
{335545029, "Install incomplete, please read chapter \"Initializing security database\" in Quick Start Guide"}, /* missing_data_structures */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */

View File

@ -729,6 +729,7 @@ static const struct {
{335545026, -901}, /* 706 ee_blr_mismatch_null */
{335545027, -901}, /* 707 ee_blr_mismatch_length */
{335545028, -406}, /* 708 ss_out_of_bounds */
{335545029, -902}, /* 709 missing_data_structures */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -729,6 +729,7 @@ static const struct {
{335545026, "42000"}, // 706 ee_blr_mismatch_null
{335545027, "42000"}, // 707 ee_blr_mismatch_length
{335545028, "42000"}, // 708 ss_out_of_bounds
{335545029, "28000"}, // 709 missing_data_structures
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -2337,7 +2337,7 @@ dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
{
impure->vlu_misc.vlu_int64 = (impure->vlu_misc.vlu_int64 << 4) + *address;
const SINT64 n = impure->vlu_misc.vlu_int64 & CONST64(0xF000000000000000);
const SINT64 n = impure->vlu_misc.vlu_int64 & FB_CONST64(0xF000000000000000);
if (n)
impure->vlu_misc.vlu_int64 ^= n >> 56;
impure->vlu_misc.vlu_int64 &= ~n;
@ -2355,7 +2355,7 @@ dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
{
impure->vlu_misc.vlu_int64 = (impure->vlu_misc.vlu_int64 << 4) + *address;
const SINT64 n = impure->vlu_misc.vlu_int64 & CONST64(0xF000000000000000);
const SINT64 n = impure->vlu_misc.vlu_int64 & FB_CONST64(0xF000000000000000);
if (n)
impure->vlu_misc.vlu_int64 ^= n >> 56;
impure->vlu_misc.vlu_int64 &= ~n;

View File

@ -29,7 +29,7 @@
#include "../jrd/ibase.h"
#include "../jrd/DatabaseSnapshot.h"
#include "../jrd/recsrc/RecordSource.h"
#include "../auth/AuthInterface.h"
#include "firebird/Auth.h"
#include "../common/security.h"
namespace Jrd {

View File

@ -6649,9 +6649,8 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options, const RefP
{
// stub instead mapUser(....);
AuthReader auth(options.dpb_auth_block);
string dummy;
PathName secureDb;
if (auth.getInfo(&name, &dummy, &secureDb))
if (auth.getInfo(&name, NULL, &secureDb))
{
if (secureDb.hasData())
{
@ -6663,7 +6662,7 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options, const RefP
else
{
auth.moveNext();
auth.getInfo(&trusted_role, &dummy, &secureDb);
auth.getInfo(&trusted_role, NULL, NULL);
}
}
}

View File

@ -52,7 +52,6 @@
#include "../jrd/thread_proto.h"
#include "../yvalve/why_proto.h"
#include "../jrd/jrd_proto.h"
#include "../common/enc_proto.h"
#include "../common/classes/alloc.h"
#include "../common/classes/init.h"
#include "../common/classes/ClumpletWriter.h"
@ -750,8 +749,7 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
// stub instead mapUser(....);
AuthReader auth(svc_auth_block);
Firebird::string method;
PathName secDb;
if (auth.getInfo(&svc_username, &method, &secDb) && method == "Win_Sspi")
if (auth.getInfo(&svc_username, &method, NULL) && method == "Win_Sspi")
{
auth.moveNext();
if (!auth.isEof())

View File

@ -62,7 +62,6 @@
#include "../jrd/tpc_proto.h"
#include "../jrd/tra_proto.h"
#include "../jrd/vio_proto.h"
#include "../common/enc_proto.h"
#include "../jrd/jrd_proto.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/TriState.h"

View File

@ -431,10 +431,9 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc)
authBlock.add(bytes, authBlockSize);
AuthReader auth(authBlock);
string dummy;
PathName secureDb;
if (auth.getInfo(&user, &dummy, &secureDb))
if (auth.getInfo(&user, NULL, &secureDb))
{
pwd = "";
adminRole = false;
@ -442,7 +441,7 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc)
{
auth.moveNext();
string trusted_role;
if (auth.getInfo(&trusted_role, &dummy, &secureDb))
if (auth.getInfo(&trusted_role, NULL, NULL))
{
adminRole = true;
}

View File

@ -115,7 +115,7 @@ public:
{
if (changeNumber != getStorage()->getChangeNumber())
update_sessions();
return trace_needs & (CONST64(1) << e);
return trace_needs & (FB_CONST64(1) << e);
}
/* DSQL-friendly routines to call Trace API hooks.

View File

@ -1,7 +1,7 @@
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
--
('2011-07-29 16:58:38', 'JRD', 0, 709)
('2011-12-22 18:36:31', 'JRD', 0, 710)
('2010-03-15 06:59:09', 'QLI', 1, 531)
--
--('2008-11-28 20:27:04', 'GDEF', 2, 346)

View File

@ -816,6 +816,7 @@ Data source : @4', NULL, NULL)
('ee_blr_mismatch_null', NULL, 'met.epp', NULL, 0, 706, NULL, 'External BLR message mismatch: invalid null descriptor at field @1', NULL, NULL)
('ee_blr_mismatch_length', NULL, 'met.epp', NULL, 0, 707, NULL, 'External BLR message mismatch: length = @1, expected @2', NULL, NULL)
('ss_out_of_bounds', NULL, 'sdl.cpp', NULL, 0, 708, NULL, 'Subscript @1 out of bounds [@2, @3]', NULL, NULL)
('missing_data_structures', NULL, 'server.cpp', NULL, 0, 709, NULL, 'Install incomplete, please read chapter "Initializing security database" in Quick Start Guide', NULL, NULL)
-- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);

View File

@ -714,6 +714,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-901, '42', '000', 0, 706, 'ee_blr_mismatch_null', NULL, NULL)
(-901, '42', '000', 0, 707, 'ee_blr_mismatch_length', NULL, NULL)
(-406, '42', '000', 0, 708, 'ss_out_of_bounds', NULL, NULL)
(-902, '28', '000', 0, 709, 'missing_data_structures', NULL, NULL)
-- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)

View File

@ -53,7 +53,6 @@
#include "../remote/remot_proto.h"
#include "../remote/proto_proto.h"
#include "../common/cvt.h"
#include "../common/enc_proto.h"
#include "../yvalve/gds_proto.h"
#include "../common/isc_f_proto.h"
#include "../common/sdl_proto.h"
@ -67,6 +66,7 @@
#include "../common/StatementMetadata.h"
#include "../auth/SecurityDatabase/LegacyClient.h"
#include "../auth/SecureRemotePassword/client/SrpClient.h"
#include "../auth/trusted/AuthSspi.h"
@ -105,34 +105,15 @@ const char* const WNET_LOCALHOST = "\\\\.";
using namespace Firebird;
namespace {
MakeUpgradeInfo<> upInfo;
// Success vector for general use
const ISC_STATUS success_vector[] = {isc_arg_gds, FB_SUCCESS, isc_arg_end};
// this sets of parameters help use same functions
// for both services and databases attachments
struct ParametersSet
{
UCHAR dummy_packet_interval, user_name,
password, password_enc, address_path, process_id, process_name;
};
const ParametersSet dpbParam = {isc_dpb_dummy_packet_interval,
isc_dpb_user_name,
isc_dpb_password,
isc_dpb_password_enc,
isc_dpb_address_path,
isc_dpb_process_id,
isc_dpb_process_name};
const ParametersSet spbParam = {isc_spb_dummy_packet_interval,
isc_spb_user_name,
isc_spb_password,
isc_spb_password_enc,
isc_spb_address_path,
isc_spb_process_id,
isc_spb_process_name};
}
namespace Remote {
// Provider stuff
class Attachment;
class Blob : public Firebird::RefCntIface<Firebird::IBlob, FB_BLOB_VERSION>
@ -552,6 +533,7 @@ void registerRedirector(Firebird::IPluginManager* iPlugin)
iPlugin->registerPluginFactory(Firebird::PluginType::Provider, "Loopback", &loopbackFactory);
Auth::registerLegacyClient(iPlugin);
Auth::registerSrpClient(iPlugin);
#ifdef TRUSTED_AUTH
Auth::registerTrustedClient(iPlugin);
#endif
@ -570,17 +552,13 @@ extern "C" void FB_PLUGIN_ENTRY_POINT(IMaster* master)
namespace Remote {
typedef GetPlugins<Auth::IClient> AuthClientPlugins;
static MakeUpgradeInfo<> upInfo;
static Rvnt* add_event(rem_port*);
static void add_other_params(rem_port*, ClumpletWriter&, const ParametersSet&);
static void add_working_directory(ClumpletWriter&, const PathName&);
static rem_port* analyze(PathName&, bool, ClumpletReader&, PathName&, bool);
static rem_port* analyze(ClntAuthBlock&, PathName&, bool, ClumpletReader&, PathName&, bool);
static rem_port* analyze_service(PathName&, bool, ClumpletReader&, bool);
static void batch_gds_receive(rem_port*, struct rmtque *, USHORT);
static void batch_dsql_fetch(rem_port*, struct rmtque *, USHORT);
static void check_response(IStatus*, Rdb*, PACKET *);
static void clear_queue(rem_port*);
static void clear_stmt_que(rem_port*, Rsr*);
static void disconnect(rem_port*);
@ -592,8 +570,8 @@ static Rvnt* find_event(rem_port*, SLONG);
static bool get_new_dpb(ClumpletWriter&, const ParametersSet&);
static void handle_error(ISC_STATUS);
static void info(IStatus*, Rdb*, P_OP, USHORT, USHORT, USHORT,
const UCHAR*, USHORT, const UCHAR*, ULONG, UCHAR*, AuthClientPlugins* authItr = NULL);
static void init(IStatus*, rem_port*, P_OP, PathName&, ClumpletWriter&);
const UCHAR*, USHORT, const UCHAR*, ULONG, UCHAR*, ClntAuthBlock* cBlock = NULL);
static void init(IStatus*, ClntAuthBlock&, rem_port*, P_OP, PathName&, ClumpletWriter&);
static Rtr* make_transaction(Rdb*, USHORT);
static void mov_dsql_message(const UCHAR*, const rem_fmt*, UCHAR*, const rem_fmt*);
static void move_error(const Arg::StatusVector& v);
@ -618,11 +596,12 @@ static void server_death(rem_port*);
static void svcstart(IStatus*, Rdb*, P_OP, USHORT, USHORT, USHORT, const UCHAR*);
static void unsupported();
static void zap_packet(PACKET *);
static void cleanDpb(Firebird::ClumpletWriter&, const ParametersSet*);
static void authFillParametersBlock(AuthClientPlugins& authItr, ClumpletWriter& dpb,
const Auth::AuthTags* tags, rem_port* port);
static void authReceiveResponse(AuthClientPlugins& authItr, rem_port* port, Rdb* rdb,
const Auth::AuthTags* tags, IStatus* status, PACKET* packet);
static void authFillParametersBlock(ClntAuthBlock& authItr, ClumpletWriter& dpb,
const ParametersSet* tags, const PathName* filename, rem_port* port);
static void authReceiveResponse(ClntAuthBlock& authItr, rem_port* port, Rdb* rdb,
const ParametersSet* tags, IStatus* status, PACKET* packet);
static AtomicCounter remote_event_id;
@ -682,7 +661,9 @@ Firebird::IAttachment* Provider::attach(IStatus* status, const char* filename,
PathName expanded_name(filename);
PathName node_name;
rem_port* port = analyze(expanded_name, user_verification, newDpb, node_name, loopback);
ClntAuthBlock cBlock(&expanded_name);
rem_port* port = analyze(cBlock, expanded_name, user_verification, newDpb, node_name, loopback);
if (!port)
{
@ -700,7 +681,7 @@ Firebird::IAttachment* Provider::attach(IStatus* status, const char* filename,
add_other_params(port, newDpb, dpbParam);
add_working_directory(newDpb, node_name);
init(status, port, op_attach, expanded_name, newDpb);
init(status, cBlock, port, op_attach, expanded_name, newDpb);
Attachment* a = new Attachment(port->port_context, filename);
a->addRef();
@ -1226,7 +1207,9 @@ Firebird::IAttachment* Provider::create(IStatus* status, const char* filename,
PathName expanded_name(filename);
PathName node_name;
rem_port* port = analyze(expanded_name, user_verification, newDpb, node_name, loopback);
ClntAuthBlock cBlock(&expanded_name);
rem_port* port = analyze(cBlock, expanded_name, user_verification, newDpb, node_name, loopback);
if (!port)
{
@ -1244,7 +1227,7 @@ Firebird::IAttachment* Provider::create(IStatus* status, const char* filename,
add_other_params(port, newDpb, dpbParam);
add_working_directory(newDpb, node_name);
init(status, port, op_create, expanded_name, newDpb);
init(status, cBlock, port, op_create, expanded_name, newDpb);
Firebird::IAttachment* a = new Attachment(rdb, filename);
a->addRef();
@ -1757,7 +1740,7 @@ Firebird::ITransaction* Statement::execute(IStatus* status, Firebird::ITransacti
receive_packet(port, packet);
if (packet->p_operation != op_sql_response)
check_response(status, rdb, packet);
REMOTE_check_response(status, rdb, packet);
else
{
port->port_statement->rsr_message->msg_address = NULL;
@ -1955,7 +1938,7 @@ Firebird::ITransaction* Attachment::execute(IStatus* status, Firebird::ITransact
receive_packet(rdb->rdb_port, packet);
if (packet->p_operation != op_sql_response)
check_response(status, rdb, packet);
REMOTE_check_response(status, rdb, packet);
else
{
message->msg_address = NULL;
@ -3161,7 +3144,7 @@ int Attachment::getSlice(IStatus* status, ITransaction* apiTra, ISC_QUAD* array_
if (packet->p_operation != op_slice)
{
check_response(status, rdb, packet);
REMOTE_check_response(status, rdb, packet);
}
return response->p_slr_length;
@ -4137,7 +4120,11 @@ Firebird::IService* Provider::attachSvc(IStatus* status, const char* service,
add_other_params(port, newSpb, spbParam);
init(status, port, op_service_attach, expanded_name, newSpb);
ClntAuthBlock cBlock(NULL);
cBlock.load(newSpb, &spbParam);
init(status, cBlock, port, op_service_attach, expanded_name, newSpb);
cBlock.saveServiceDataTo(port);
Firebird::IService* s = new Service(rdb);
s->addRef();
@ -4241,11 +4228,6 @@ void Service::query(IStatus* status,
* Functional description
* Provide information on service object.
*
* NOTE: The parameter RESERVED must not be used
* for any purpose as there are networking issues
* involved (as with any handle that goes over the
* network). This parameter will be implemented at
* a later date.
**************************************/
try
{
@ -4263,11 +4245,12 @@ void Service::query(IStatus* status,
unsupported();
}
AuthClientPlugins authItr(PluginType::AuthClient, FB_AUTH_CLIENT_VERSION, upInfo);
ClntAuthBlock cBlock(NULL);
cBlock.loadServiceDataFrom(port);
info(status, rdb, op_service_info, rdb->rdb_id, 0,
sendLength, sendItems, receiveLength, receiveItems,
bufferLength, buffer, &authItr);
bufferLength, buffer, &cBlock);
}
catch (const Exception& ex)
{
@ -4610,7 +4593,7 @@ void Attachment::transactRequest(IStatus* status, ITransaction* apiTra,
if (packet->p_operation != op_transact_response)
{
check_response(status, rdb, packet);
REMOTE_check_response(status, rdb, packet);
}
}
catch (const Exception& ex)
@ -4842,7 +4825,30 @@ static void add_working_directory(ClumpletWriter& dpb, const PathName& node_name
}
static rem_port* analyze(PathName& file_name,
static void authenticateStep0(ClntAuthBlock& wire)
{
for (LocalStatus s; wire.plugins.hasData(); wire.plugins.next())
{
switch(wire.plugins.plugin()->authenticate(&s, &wire))
{
case Auth::AUTH_SUCCESS:
case Auth::AUTH_MORE_DATA:
return;
case Auth::AUTH_FAILED:
gds__log_status("Authentication, client plugin:", s.get());
(Arg::Gds(isc_login)
#ifdef DEV_BUILD
<< Arg::StatusVector(s.get())
#endif
).raise();
break; // compiler silencer
}
}
}
static rem_port* analyze(ClntAuthBlock& cBlock,
PathName& file_name,
bool uv_flag,
ClumpletReader& dpb,
PathName& node_name,
@ -4869,10 +4875,13 @@ static rem_port* analyze(PathName& file_name,
// Analyze the file name to see if a remote connection is required. If not,
// quietly (sic) return.
cBlock.load(dpb, &dpbParam);
authenticateStep0(cBlock);
#ifdef WIN_NT
if (ISC_analyze_protocol(PROTOCOL_XNET, file_name, node_name))
{
return XNET_analyze(file_name, uv_flag);
return XNET_analyze(&cBlock, file_name, uv_flag);
}
if (ISC_analyze_protocol(PROTOCOL_WNET, file_name, node_name) ||
@ -4882,7 +4891,7 @@ static rem_port* analyze(PathName& file_name,
{
node_name = WNET_LOCALHOST;
}
return WNET_analyze(file_name, node_name.c_str(), uv_flag);
return WNET_analyze(&cBlock, file_name, node_name.c_str(), uv_flag);
}
#endif
@ -4893,7 +4902,7 @@ static rem_port* analyze(PathName& file_name,
{
node_name = INET_LOCALHOST;
}
return INET_analyze(file_name, node_name.c_str(), uv_flag, dpb);
return INET_analyze(&cBlock, file_name, node_name.c_str(), uv_flag, dpb);
}
// We have a local connection string. If it's a file on a network share,
@ -4907,7 +4916,7 @@ static rem_port* analyze(PathName& file_name,
if (ISC_analyze_pclan(expanded_name, node_name))
{
port = WNET_analyze(expanded_name, node_name.c_str(), uv_flag);
port = WNET_analyze(&cBlock, expanded_name, node_name.c_str(), uv_flag);
}
#endif
@ -4917,7 +4926,7 @@ static rem_port* analyze(PathName& file_name,
PathName expanded_name = file_name;
if (ISC_analyze_nfs(expanded_name, node_name))
{
port = INET_analyze(expanded_name, node_name.c_str(), uv_flag, dpb);
port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), uv_flag, dpb);
}
}
#endif
@ -4932,17 +4941,17 @@ static rem_port* analyze(PathName& file_name,
#ifdef WIN_NT
if (!port)
{
port = XNET_analyze(file_name, uv_flag);
port = XNET_analyze(&cBlock, file_name, uv_flag);
}
if (!port)
{
port = WNET_analyze(file_name, WNET_LOCALHOST, uv_flag);
port = WNET_analyze(&cBlock, file_name, WNET_LOCALHOST, uv_flag);
}
#endif
if (!port)
{
port = INET_analyze(file_name, INET_LOCALHOST, uv_flag, dpb);
port = INET_analyze(&cBlock, file_name, INET_LOCALHOST, uv_flag, dpb);
}
}
}
@ -4971,15 +4980,15 @@ static rem_port* analyze_service(PathName& service_name,
* Otherwise, return NULL.
*
**************************************/
PathName node_name;
// Analyze the service name to see if a remote connection is required. If not,
// quietly (sic) return.
PathName node_name;
#if defined(WIN_NT)
if (ISC_analyze_protocol(PROTOCOL_XNET, service_name, node_name))
{
return XNET_analyze(service_name, uv_flag);
return XNET_analyze(cBlock, service_name, uv_flag);
}
if (ISC_analyze_protocol(PROTOCOL_WNET, service_name, node_name) ||
@ -4989,7 +4998,7 @@ static rem_port* analyze_service(PathName& service_name,
{
node_name = WNET_LOCALHOST;
}
return WNET_analyze(service_name, node_name.c_str(), uv_flag);
return WNET_analyze(cBlock, service_name, node_name.c_str(), uv_flag);
}
#endif
@ -5000,7 +5009,7 @@ static rem_port* analyze_service(PathName& service_name,
{
node_name = INET_LOCALHOST;
}
return INET_analyze(service_name, node_name.c_str(), uv_flag, spb);
return INET_analyze(NULL, service_name, node_name.c_str(), uv_flag, spb);
}
rem_port* port = NULL;
@ -5016,17 +5025,17 @@ static rem_port* analyze_service(PathName& service_name,
#if defined(WIN_NT)
if (!port)
{
port = XNET_analyze(service_name, uv_flag);
port = XNET_analyze(cBlock, service_name, uv_flag);
}
if (!port)
{
port = WNET_analyze(service_name, WNET_LOCALHOST, uv_flag);
port = WNET_analyze(cBlock, service_name, WNET_LOCALHOST, uv_flag);
}
#endif
if (!port)
{
port = INET_analyze(service_name, INET_LOCALHOST, uv_flag, spb);
port = INET_analyze(NULL, service_name, INET_LOCALHOST, uv_flag, spb);
}
}
}
@ -5165,7 +5174,7 @@ static void batch_dsql_fetch(rem_port* port,
statement->rsr_flags.set(Rsr::STREAM_ERR);
try
{
check_response(&status, rdb, packet);
REMOTE_check_response(&status, rdb, packet);
statement->saveException(status.get(), false);
}
catch (const Exception& ex)
@ -5321,7 +5330,7 @@ static void batch_gds_receive(rem_port* port,
try
{
LocalStatus status;
check_response(&status, rdb, packet);
REMOTE_check_response(&status, rdb, packet);
#ifdef DEBUG
fprintf(stderr, "End of batch. rows pending = %d\n", tail->rrq_rows_pending);
#endif
@ -5368,85 +5377,6 @@ static void batch_gds_receive(rem_port* port,
}
static void check_response(IStatus* warning, Rdb* rdb, PACKET* packet)
{
/**************************************
*
* c h e c k _ r e s p o n s e
*
**************************************
*
* Functional description
* Check response to a remote call.
*
**************************************/
// Get status vector
const ISC_STATUS* vector = success_vector;
if (packet->p_resp.p_resp_status_vector)
{
vector = packet->p_resp.p_resp_status_vector->value();
}
// Translate any gds codes into local operating specific codes
SimpleStatusVector newVector;
rem_port* port = rdb->rdb_port;
while (*vector != isc_arg_end)
{
const ISC_STATUS vec = *vector++;
newVector.push(vec);
switch ((USHORT) vec)
{
case isc_arg_warning:
case isc_arg_gds:
if (port->port_protocol < PROTOCOL_VERSION10)
{
fb_assert(vec == isc_arg_gds);
newVector.push(gds__encode(*vector++, 0));
}
else
newVector.push(*vector++);
break;
case isc_arg_cstring:
newVector.push(*vector++);
// fall down
default:
newVector.push(*vector++);
break;
}
}
newVector.push(isc_arg_end);
vector = newVector.begin();
const ISC_STATUS pktErr = vector[1];
if (pktErr == isc_shutdown || pktErr == isc_att_shutdown)
{
port->port_flags |= PORT_rdb_shutdown;
}
if ((packet->p_operation == op_response || packet->p_operation == op_response_piggyback) &&
!vector[1])
{
warning->set(vector);
return;
}
if (!vector[1])
{
Arg::Gds(isc_net_read_err).raise();
}
status_exception::raise(vector);
}
static void clear_queue(rem_port* port)
{
/**************************************
@ -5668,7 +5598,7 @@ static int fetch_blob(IStatus* status,
if (packet->p_operation == op_fetch_response)
receive_response(status, rdb, packet);
else
check_response(status, rdb, packet);
REMOTE_check_response(status, rdb, packet);
return packet->p_sqldata.p_sqldata_status;
}
@ -5721,25 +5651,6 @@ static bool get_new_dpb(ClumpletWriter& dpb, const ParametersSet& par)
}
}
/* #ifndef NO_PASSWORD_ENCRYPTION */
#ifdef NEVERDEF
if (dpb.find(par.password))
{
string password;
dpb.getString(password);
dpb.deleteClumplet();
if (!dpb.find(isc_dpb_utf8_filename))
ISC_systemToUtf8(password);
ISC_unescape(password);
TEXT pwt[Auth::MAX_PASSWORD_LENGTH + 2];
ENC_crypt(pwt, sizeof pwt, password.c_str(), Auth::PASSWORD_SALT);
password = pwt + 2;
dpb.insertString(par.password_enc, password);
}
#endif
return dpb.find(par.user_name);
}
@ -5774,7 +5685,7 @@ static void info(IStatus* status,
const UCHAR* recv_items,
ULONG buffer_length,
UCHAR* buffer,
AuthClientPlugins* authItr)
ClntAuthBlock* cBlock)
{
/**************************************
*
@ -5817,8 +5728,9 @@ static void info(IStatus* status,
if (operation == op_service_info)
{
// Probably communicate with services auth
fb_assert(authItr);
authReceiveResponse(*authItr, rdb->rdb_port, rdb, &Auth::SVC_QUERY_LIST, status, packet);
fb_assert(cBlock);
HANDSHAKE_DEBUG(fprintf(stderr, "info() calls authReceiveResponse\n"));
authReceiveResponse(*cBlock, rdb->rdb_port, rdb, &spbInfoParam, status, packet);
}
else
{
@ -5836,42 +5748,40 @@ static void info(IStatus* status,
}
// Let plugins try to add data to DPB in order to avoid extra network roundtrip
static void authFillParametersBlock(AuthClientPlugins& authItr, ClumpletWriter& dpb,
const Auth::AuthTags* tags, rem_port* port)
static void authFillParametersBlock(ClntAuthBlock& cBlock, ClumpletWriter& dpb,
const ParametersSet* tags, const PathName* filename, rem_port* port)
{
LocalStatus s;
Auth::DpbImplementation di(dpb);
bool working = true;
cBlock.resetDataFromPlugin();
while (working && authItr.hasData())
for (; cBlock.plugins.hasData(); cBlock.plugins.next())
{
if (port->port_protocol >= PROTOCOL_VERSION13 ||
(port->port_protocol >= PROTOCOL_VERSION11 && Auth::legacy(authItr.name())))
REMOTE_legacy_auth(cBlock.plugins.name(), port->port_protocol))
{
cBlock.resetDataFromPlugin();
// OK to use plugin
switch(authItr.plugin()->startAuthentication(&s, tags, &di))
switch(cBlock.plugins.plugin()->authenticate(&s, &cBlock))
{
case Auth::AUTH_SUCCESS:
working = false;
break;
case Auth::AUTH_MORE_DATA:
HANDSHAKE_DEBUG(fprintf(stderr, "FPB: plugin %s is OK\n", cBlock.plugins.name()));
cleanDpb(dpb, tags);
cBlock.extractDataFromPluginTo(dpb, tags, port->port_protocol);
return;
case Auth::AUTH_FAILED:
HANDSHAKE_DEBUG(fprintf(stderr, "FPB: plugin %s FAILED\n", cBlock.plugins.name()));
(Arg::Gds(isc_login) << Arg::StatusVector(s.get())).raise();
break; // compiler silencer
default:
authItr.next();
break;
}
}
else
{
authItr.next();
}
HANDSHAKE_DEBUG(fprintf(stderr, "FPB: try next plugin, %s skipped\n", cBlock.plugins.name()));
}
}
static void authReceiveResponse(AuthClientPlugins& authItr, rem_port* port, Rdb* rdb,
const Auth::AuthTags* tags, IStatus* status, PACKET* packet)
static void authReceiveResponse(ClntAuthBlock& cBlock, rem_port* port, Rdb* rdb,
const ParametersSet* tags, IStatus* status, PACKET* packet)
{
LocalStatus s;
@ -5887,27 +5797,31 @@ static void authReceiveResponse(AuthClientPlugins& authItr, rem_port* port, Rdb*
switch(packet->p_operation)
{
case op_trusted_auth:
HANDSHAKE_DEBUG(fprintf(stderr, "RR:TA\n"));
d = &packet->p_trau.p_trau_data;
break;
case op_cont_auth:
d = &packet->p_auth_cont.p_data;
n = &packet->p_auth_cont.p_name;
HANDSHAKE_DEBUG(fprintf(stderr, "RR:CA d=%d n=%d '%.*s' 0x%x\n", d->cstr_length, n->cstr_length,
n->cstr_length, n->cstr_address, n->cstr_address ? n->cstr_address[0] : 0));
break;
default:
check_response(status, rdb, packet);
HANDSHAKE_DEBUG(fprintf(stderr, "RR: Default answer\n"));
REMOTE_check_response(status, rdb, packet);
// successfully attached
HANDSHAKE_DEBUG(fprintf(stderr, "RR: OK!\n"));
rdb->rdb_id = packet->p_resp.p_resp_object;
return;
}
bool contFlag = true;
if (n && n->cstr_length && authItr.hasData())
if (n && n->cstr_length && cBlock.plugins.hasData())
{
// if names match, do not change instance
if (strlen(authItr.name()) == n->cstr_length &&
memcmp(authItr.name(), n->cstr_address, n->cstr_length) == 0)
if (strlen(cBlock.plugins.name()) == n->cstr_length &&
memcmp(cBlock.plugins.name(), n->cstr_address, n->cstr_length) == 0)
{
n = NULL;
}
@ -5916,63 +5830,37 @@ static void authReceiveResponse(AuthClientPlugins& authItr, rem_port* port, Rdb*
if (n && n->cstr_length)
{
// switch to other plugin
string tmp(n->cstr_address, n->cstr_length);
authItr.set(tmp.c_str());
if (authItr.hasData())
PathName tmp(n->cstr_address, n->cstr_length);
if (!cBlock.checkPluginName(tmp))
{
Auth::Result rc = authItr.plugin()->startAuthentication(&s, tags, NULL);
if (rc == Auth::AUTH_FAILED)
{
break;
}
if (rc != Auth::AUTH_MORE_DATA)
{
contFlag = false;
}
}
else
{
contFlag = false;
packet->p_trau.p_trau_data.cstr_length = 0;
break;
}
cBlock.plugins.set(tmp.c_str());
}
if (contFlag)
if (!cBlock.plugins.hasData())
{
// continue auth
if (!authItr.hasData())
{
break;
}
if (authItr.plugin()->contAuthentication(&s, d->cstr_address, d->cstr_length) == Auth::AUTH_FAILED)
{
break;
}
break;
}
if (!authItr.hasData())
cBlock.storeDataForPlugin(d->cstr_length, d->cstr_address);
if (cBlock.plugins.plugin()->authenticate(&s, &cBlock) == Auth::AUTH_FAILED)
{
break;
}
// send answer (may be empty) to server
packet->p_operation = op_trusted_auth;
d = &packet->p_trau.p_trau_data;
d->cstr_allocated = 0;
// violate constness here safely - send operation does not modify data
authItr.plugin()->getData(const_cast<const unsigned char**>(&d->cstr_address),
&d->cstr_length);
packet->p_operation = op_cont_auth;
cBlock.extractDataFromPluginTo(&packet->p_auth_cont);
send_packet(port, packet);
memset(&packet->p_auth_cont, 0, sizeof packet->p_auth_cont);
}
// If we have exited from the cycle, this mean auth failed
(Arg::Gds(isc_login) << Arg::StatusVector(s.get())).raise();
}
static void init(IStatus* status, rem_port* port, P_OP op, PathName& file_name,
static void init(IStatus* status, ClntAuthBlock& cBlock, rem_port* port, P_OP op, PathName& file_name,
ClumpletWriter& dpb)
{
/**************************************
@ -5994,11 +5882,6 @@ static void init(IStatus* status, rem_port* port, P_OP op, PathName& file_name,
MemoryPool& pool = *getDefaultMemoryPool();
port->port_deferred_packets = FB_NEW(pool) PacketQueue(pool);
AuthClientPlugins authItr(PluginType::AuthClient, FB_AUTH_CLIENT_VERSION, upInfo);
authFillParametersBlock(authItr, dpb,
op == op_service_attach ? &Auth::SVC_ATTACH_LIST : &Auth::DB_ATTACH_LIST,
port);
if (port->port_protocol < PROTOCOL_VERSION12)
{
// This is FB < 2.5. Lets remove that not recognized DPB and convert the UTF8
@ -6034,6 +5917,12 @@ static void init(IStatus* status, rem_port* port, P_OP op, PathName& file_name,
}
}
HANDSHAKE_DEBUG(fprintf(stderr, "init calls authFillParametersBlock\n"));
authFillParametersBlock(cBlock, dpb,
op == op_service_attach ? &spbParam : &dpbParam,
op == op_service_attach ? NULL : &file_name,
port);
// Make attach packet
P_ATCH* attach = &packet->p_atch;
packet->p_operation = op;
@ -6044,9 +5933,8 @@ static void init(IStatus* status, rem_port* port, P_OP op, PathName& file_name,
send_packet(port, packet);
authReceiveResponse(authItr, port, rdb,
op == op_service_attach ? &Auth::SVC_ATTACH_LIST : &Auth::DB_ATTACH_LIST,
status, packet);
authReceiveResponse(cBlock, port, rdb,
op == op_service_attach ? &spbParam : &dpbParam, status, packet);
}
catch (const Exception&)
{
@ -6205,7 +6093,7 @@ static void receive_after_start(Rrq* request, USHORT msg_type)
try
{
LocalStatus status;
check_response(&status, rdb, packet);
REMOTE_check_response(&status, rdb, packet);
request->saveStatus(&status);
}
catch (const Exception& ex)
@ -6321,7 +6209,7 @@ static void receive_packet_noqueue(rem_port* port, PACKET* packet)
try
{
LocalStatus status;
check_response(&status, rdb, &p->packet);
REMOTE_check_response(&status, rdb, &p->packet);
statement->saveException(status.get(), false);
}
catch (const Exception& ex)
@ -6464,7 +6352,7 @@ static void receive_response(IStatus* status, Rdb* rdb, PACKET* packet)
**************************************/
receive_packet(rdb->rdb_port, packet);
check_response(status, rdb, packet);
REMOTE_check_response(status, rdb, packet);
}
@ -6924,8 +6812,10 @@ static void svcstart(IStatus* status,
// Get ready for multi-hop auth
ClumpletWriter send(ClumpletReader::SpbStart, MAX_DPB_SIZE, items, item_length);
AuthClientPlugins authItr(PluginType::AuthClient, FB_AUTH_CLIENT_VERSION, upInfo);
authFillParametersBlock(authItr, send, &Auth::SVC_START_LIST, rdb->rdb_port);
ClntAuthBlock cBlock(NULL);
cBlock.loadServiceDataFrom(rdb->rdb_port);
HANDSHAKE_DEBUG(fprintf(stderr, "start calls authFillParametersBlock\n"));
authFillParametersBlock(cBlock, send, &spbStartParam, NULL, rdb->rdb_port);
// Build the primary packet to get the operation started.
PACKET* packet = &rdb->rdb_packet;
@ -6945,7 +6835,7 @@ static void svcstart(IStatus* status,
try
{
authReceiveResponse(authItr, rdb->rdb_port, rdb, &Auth::SVC_START_LIST, status, packet);
authReceiveResponse(cBlock, rdb->rdb_port, rdb, &spbStartParam, status, packet);
}
catch (const Exception&)
{
@ -7059,4 +6949,193 @@ Transaction* Attachment::remoteTransactionInterface(ITransaction* apiTra)
return static_cast<Transaction*>(valid);
}
static void cleanDpb(Firebird::ClumpletWriter& dpb, const ParametersSet* tags)
{
dpb.deleteWithTag(tags->password);
dpb.deleteWithTag(tags->password_enc);
dpb.deleteWithTag(tags->trusted_auth);
}
} //namespace Remote
ClntAuthBlock::ClntAuthBlock(const Firebird::PathName* fileName)
: pluginList(getPool()), userName(getPool()), password(getPool()),
dataForPlugin(getPool()), dataFromPlugin(getPool()),
hasCryptKey(false),
plugins(PluginType::AuthClient, FB_AUTH_CLIENT_VERSION, upInfo),
authComplete(false), firstTime(true)
{
reset(fileName);
}
void ClntAuthBlock::resetDataFromPlugin()
{
dataFromPlugin.clear();
}
void ClntAuthBlock::extractDataFromPluginTo(Firebird::ClumpletWriter& dpb,
const ParametersSet* tags,
int protocol)
{
if (!dataFromPlugin.hasData())
{
return;
}
PathName pluginName = getPluginName();
if (protocol >= PROTOCOL_VERSION13)
{
if (firstTime)
{
fb_assert(tags->plugin_name && tags->plugin_list);
if (pluginName.hasData())
{
dpb.insertPath(tags->plugin_name, pluginName);
}
dpb.insertPath(tags->plugin_list, pluginList);
firstTime = false;
HANDSHAKE_DEBUG(fprintf(stderr, "first time - added plugName & pluginList\n"));
}
fb_assert(tags->specific_data);
dpb.insertBytes(tags->specific_data, dataFromPlugin.begin(), dataFromPlugin.getCount());
HANDSHAKE_DEBUG(fprintf(stderr, "Added %" SIZEFORMAT " bytes of spec data with tag %d\n",
dataFromPlugin.getCount(), tags->specific_data));
return;
}
if (REMOTE_legacy_auth(pluginName.c_str(), PROTOCOL_VERSION10)) // dataFromPlugin is encrypted password
{
fb_assert(tags->password_enc);
dpb.insertBytes(tags->password_enc, dataFromPlugin.begin(), dataFromPlugin.getCount());
return;
}
fb_assert(REMOTE_legacy_auth(pluginName.c_str(), protocol)); // dataFromPlugin must be trustedAuth
fb_assert(tags->trusted_auth);
dpb.insertBytes(tags->trusted_auth, dataFromPlugin.begin(), dataFromPlugin.getCount());
}
static inline void makeUtfString(bool uft8Convert, Firebird::string& s)
{
if (uft8Convert)
{
ISC_systemToUtf8(s);
}
ISC_unescape(s);
}
void ClntAuthBlock::load(Firebird::ClumpletReader& dpb, const ParametersSet* tags)
{
bool uft8Convert = !dpb.find(isc_dpb_utf8_filename);
for (dpb.rewind(); !dpb.isEof(); dpb.moveNext())
{
const UCHAR t = dpb.getClumpTag();
if (t == tags->user_name)
{
dpb.getString(userName);
makeUtfString(uft8Convert, userName);
HANDSHAKE_DEBUG(fprintf(stderr, "Loaded from PB user = %s\n", userName.c_str()));
userName.upper();
}
else if (t == tags->password)
{
makeUtfString(uft8Convert, password);
dpb.getString(password);
HANDSHAKE_DEBUG(fprintf(stderr, "Loaded from PB password = %s\n", password.c_str()));
}
else if (t == tags->encrypt_key)
{
hasCryptKey = true;
HANDSHAKE_DEBUG(fprintf(stderr, "PB contains crypt key - need encrypted line to pass\n"));
}
}
}
void ClntAuthBlock::extractDataFromPluginTo(P_AUTH_CONT* to)
{
to->p_data.cstr_length = dataFromPlugin.getCount();
to->p_data.cstr_address = dataFromPlugin.begin();
to->p_data.cstr_allocated = 0;
PathName pluginName = getPluginName();
to->p_name.cstr_length = pluginName.length();
to->p_name.cstr_address = (UCHAR*)(pluginName.c_str());
to->p_name.cstr_allocated = 0;
HANDSHAKE_DEBUG(fprintf(stderr, "extractDataFromPluginTo added plugin name (%d) and data (%d)\n",
to->p_name.cstr_length, to->p_data.cstr_length));
if (firstTime)
{
to->p_list.cstr_length = pluginList.length();
to->p_list.cstr_address = (UCHAR*)(pluginList.c_str());
to->p_list.cstr_allocated = 0;
HANDSHAKE_DEBUG(fprintf(stderr, "extractDataFromPluginTo added plugin list (%d len) to packet\n",
to->p_list.cstr_length));
firstTime = false;
}
else
{
to->p_list.cstr_length = 0;
}
}
const char* ClntAuthBlock::getLogin()
{
return userName.nullStr();
}
const char* ClntAuthBlock::getPassword()
{
return password.nullStr();
}
const unsigned char* ClntAuthBlock::getData(unsigned int* length)
{
*length = dataForPlugin.getCount();
return (*length) ? dataForPlugin.begin() : NULL;
}
void ClntAuthBlock::putData(unsigned int length, const void* data)
{
void* to = dataFromPlugin.getBuffer(length);
memcpy(to, data, length);
}
int ClntAuthBlock::release()
{
if (--refCounter != 0)
return 1;
delete this;
return 0;
}
bool ClntAuthBlock::checkPluginName(Firebird::PathName& nameToCheck)
{
Remote::ParsedList parsed;
REMOTE_parseList(parsed, pluginList);
for (unsigned i = 0; i < parsed.getCount(); ++i)
{
if (parsed[i] == nameToCheck)
{
return true;
}
}
return false;
}
void ClntAuthBlock::saveServiceDataTo(rem_port* port)
{
port->port_user_name = userName;
port->port_password = password;
}
void ClntAuthBlock::loadServiceDataFrom(rem_port* port)
{
userName = port->port_user_name;
password = port->port_password;
}

View File

@ -531,10 +531,11 @@ static Firebird::GlobalPtr<Firebird::Mutex> port_mutex;
static Firebird::GlobalPtr<PortsCleanup> inet_ports;
rem_port* INET_analyze(const Firebird::PathName& file_name,
rem_port* INET_analyze(ClntAuthBlock* cBlock,
const Firebird::PathName& file_name,
const TEXT* node_name,
bool uv_flag,
Firebird::ClumpletReader &dpb)
ClumpletReader &dpb)
{
/**************************************
*
@ -559,7 +560,12 @@ rem_port* INET_analyze(const Firebird::PathName& file_name,
PACKET* packet = &rdb->rdb_packet;
// Pick up some user identification information
Firebird::ClumpletWriter user_id(Firebird::ClumpletReader::UnTagged, MAX_DPB_SIZE);
Firebird::ClumpletWriter user_id(Firebird::ClumpletReader::UnTagged, 64000);
if (cBlock)
{
cBlock->extractDataFromPluginTo(user_id);
}
Firebird::string buffer;
int eff_gid;
int eff_uid;
@ -604,7 +610,7 @@ rem_port* INET_analyze(const Firebird::PathName& file_name,
copy_p_cnct_repeat_array(cnct->p_cnct_versions, protocols_to_try1, cnct->p_cnct_count);
// Try connection using first set of protocols. punt if error
// Try connection using first set of protocols
rem_port* port = inet_try_connect(packet, rdb, file_name, node_name, dpb);
@ -630,15 +636,51 @@ rem_port* INET_analyze(const Firebird::PathName& file_name,
port = inet_try_connect(packet, rdb, file_name, node_name, dpb);
}
if (packet->p_operation != op_accept)
P_ACPT* accept = NULL;
switch (packet->p_operation)
{
case op_accept_data:
accept = &packet->p_acpd;
if (cBlock)
{
cBlock->storeDataForPlugin(packet->p_acpd.p_acpt_data.cstr_length,
packet->p_acpd.p_acpt_data.cstr_address);
cBlock->authComplete = packet->p_acpd.p_acpt_authenticated;
}
break;
case op_accept:
if (cBlock)
{
cBlock->reset(&file_name);
}
accept = &packet->p_acpt;
break;
case op_response:
try
{
Firebird::LocalStatus warning; // Ignore connect warnings for a while
REMOTE_check_response(&warning, rdb, packet);
}
catch(const Firebird::Exception&)
{
disconnect(port);
delete rdb;
throw;
}
// fall through - response is not a required accept
default:
disconnect(port);
delete rdb;
Arg::Gds(isc_connect_reject).raise();
break;
}
port->port_protocol = packet->p_acpt.p_acpt_version;
fb_assert(accept);
fb_assert(port);
port->port_protocol = accept->p_acpt_version;
// once we've decided on a protocol, concatenate the version
// string to reflect it...
@ -647,19 +689,19 @@ rem_port* INET_analyze(const Firebird::PathName& file_name,
delete port->port_version;
port->port_version = REMOTE_make_string(temp.c_str());
if (packet->p_acpt.p_acpt_architecture == ARCHITECTURE) {
if (accept->p_acpt_architecture == ARCHITECTURE) {
port->port_flags |= PORT_symmetric;
}
if (packet->p_acpt.p_acpt_type == ptype_rpc) {
if (accept->p_acpt_type == ptype_rpc) {
port->port_flags |= PORT_rpc;
}
if (packet->p_acpt.p_acpt_type != ptype_out_of_band) {
if (accept->p_acpt_type != ptype_out_of_band) {
port->port_flags |= PORT_no_oob;
}
if (packet->p_acpt.p_acpt_type == ptype_lazy_send) {
if (accept->p_acpt_type == ptype_lazy_send) {
port->port_flags |= PORT_lazy;
}
@ -1192,11 +1234,8 @@ static bool accept_connection(rem_port* port, const P_CNCT* cnct)
} // end scope
#endif // !WIN_NT
// store FULL user identity in port_user_name for security purposes
Firebird::string temp;
temp.printf("%s.%ld.%ld", name.c_str(), eff_gid, eff_uid);
port->port_user_name = REMOTE_make_string(temp.c_str());
// store user identity in port_user_name
port->port_user_name = name;
port->port_protocol_str = REMOTE_make_string("TCPv4");
@ -3076,6 +3115,7 @@ static bool packet_receive(rem_port* port, UCHAR* buffer, SSHORT buffer_length,
}
n = recv(port->port_handle, reinterpret_cast<char*>(buffer), buffer_length, 0);
// ->decrypt
inetErrNo = INET_ERRNO;
if (n != -1 || !INTERRUPT_ERROR(inetErrNo))
@ -3144,6 +3184,8 @@ static bool packet_send( rem_port* port, const SCHAR* buffer, SSHORT buffer_leng
const char* data = buffer;
SSHORT length = buffer_length;
// ->encrypt
while (length)
{
#ifdef DEBUG

View File

@ -31,7 +31,8 @@ namespace Firebird
class ClumpletReader;
}
rem_port* INET_analyze(const Firebird::PathName&, const TEXT*, bool, Firebird::ClumpletReader&);
rem_port* INET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*,
bool, Firebird::ClumpletReader&);
rem_port* INET_connect(const TEXT*, struct packet*, USHORT, Firebird::ClumpletReader*);
rem_port* INET_reconnect(SOCKET);
rem_port* INET_server(SOCKET);

View File

@ -507,7 +507,7 @@ static bool accept_connection( rem_port* port, const P_CNCT* cnct)
{
case CNCT_user:
id.getString(name);
port->port_user_name = REMOTE_make_string(name.c_str());
port->port_user_name = name;
break;
case CNCT_passwd:

View File

@ -246,6 +246,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
p_cnct::p_cnct_repeat* tail;
const rem_port* port;
P_ACPT *accept;
P_ACPD *accept_with_data;
P_ATCH *attach;
P_RESP *response;
P_CMPL *compile;
@ -329,6 +330,18 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
DEBUG_PRINTSIZE(xdrs, p->p_operation);
return P_TRUE(xdrs, p);
case op_accept_data:
accept_with_data = &p->p_acpd;
MAP(xdr_short, reinterpret_cast<SSHORT&>(accept_with_data->p_acpt_version));
MAP(xdr_enum, reinterpret_cast<xdr_op&>(accept_with_data->p_acpt_architecture));
MAP(xdr_u_short, accept_with_data->p_acpt_type);
MAP(xdr_cstring, accept_with_data->p_acpt_data);
MAP(xdr_cstring, accept_with_data->p_acpt_plugin);
MAP(xdr_u_short, accept_with_data->p_acpt_authenticated);
//??? fprintf(stderr, "data length %d\n", accept_with_data->p_acpt_data.cstr_length);
DEBUG_PRINTSIZE(xdrs, p->p_operation);
return P_TRUE(xdrs, p);
case op_connect_request:
case op_aux_connect:
request = &p->p_req;
@ -755,6 +768,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
P_AUTH_CONT* auth = &p->p_auth_cont;
MAP(xdr_cstring, auth->p_data);
MAP(xdr_cstring, auth->p_name);
MAP(xdr_cstring, auth->p_list);
DEBUG_PRINTSIZE(xdrs, p->p_operation);
return P_TRUE(xdrs, p);

View File

@ -99,8 +99,7 @@ const USHORT FB_PROTOCOL_MASK = static_cast<USHORT>(~FB_PROTOCOL_FLAG);
const USHORT PROTOCOL_VERSION11 = (FB_PROTOCOL_FLAG | 11);
// Protocol 12 has support for asynchronous call op_cancel.
// Currently implemented asynchronously only for TCP/IP
// on superserver and superclassic.
// Currently implemented asynchronously only for TCP/IP.
const USHORT PROTOCOL_VERSION12 = (FB_PROTOCOL_FLAG | 12);
@ -305,6 +304,8 @@ enum P_OP
op_ping = 93,
op_accept_data = 94, // Server accepts connection and returns some data to client
op_max
};
@ -397,7 +398,10 @@ const UCHAR CNCT_host = 4;
const UCHAR CNCT_group = 5; // Effective Unix group id
const UCHAR CNCT_user_verification = 6; // Attach/create using this connection
// will use user verification
const UCHAR CNCT_specific_data = 7; // Some data, needed for user verification on server
const UCHAR CNCT_plugin_name = 8; // Name of plugin, which generated that data
const UCHAR CNCT_login = 9; // Same data as isc_dpb_user_name
const UCHAR CNCT_plugin_list = 10; // List of plugins, available on client
typedef struct bid // BLOB ID
{
@ -430,6 +434,16 @@ typedef struct p_acpt
USHORT p_acpt_type; // Minimum type
} P_ACPT;
// Accept Block with Data (Server response to connect block, start with P.13)
struct p_acpd : public p_acpt
{
CSTRING p_acpt_data; // Returned auth data
CSTRING p_acpt_plugin; // Plugin to continue with
USHORT p_acpt_authenticated; // Auth complete in single step (few! strange...)
};
typedef p_acpd P_ACPD;
// Generic Response block
typedef struct p_resp
@ -644,8 +658,9 @@ typedef struct p_trau
typedef struct p_auth_continue
{
CSTRING p_data; // Request
CSTRING p_data; // Specific data
CSTRING p_name; // Plugin name
CSTRING p_list; // Plugin list
} P_AUTH_CONT;
struct p_update_account
@ -684,6 +699,7 @@ typedef struct packet
P_OP p_operation; // Operation/packet type
P_CNCT p_cnct; // Connect block
P_ACPT p_acpt; // Accept connection
P_ACPD p_acpd; // Accept connection with data
P_RESP p_resp; // Generic response to a call
P_ATCH p_atch; // Attach or create database
P_RLSE p_rlse; // Release object

View File

@ -24,11 +24,27 @@
#ifndef REMOTE_REMOT_PROTO_H
#define REMOTE_REMOT_PROTO_H
#include "../common/classes/fb_string.h"
#include "../common/config/config.h"
#include "../common/classes/RefCounted.h"
#include "../common/classes/objects_array.h"
#include "../common/xdr.h"
#include "../remote/protocol.h"
namespace Firebird
{
class ClumpletReader;
}
namespace Remote
{
typedef Firebird::ObjectsArray<Firebird::PathName> ParsedList;
}
struct rem_port;
struct rem_fmt;
struct Rdb;
void REMOTE_cleanup_transaction (struct Rtr *);
ULONG REMOTE_compute_batch_size (rem_port*, USHORT, P_OP, const rem_fmt*);
void REMOTE_get_timeout_params(rem_port* port, Firebird::ClumpletReader* pb);
@ -41,6 +57,12 @@ void REMOTE_reset_request (struct Rrq *, struct RMessage*);
void REMOTE_reset_statement (struct Rsr *);
void REMOTE_save_status_strings (ISC_STATUS *);
bool_t REMOTE_getbytes (XDR*, SCHAR*, u_int);
bool REMOTE_legacy_auth(const char* nm, int protocol);
Firebird::RefPtr<Config> REMOTE_get_config(const Firebird::PathName* dbName);
void REMOTE_parseList(Remote::ParsedList&, Firebird::PathName);
void REMOTE_mergeList(Firebird::PathName& list, const Remote::ParsedList& parsed);
void REMOTE_check_response(Firebird::IStatus* warning, Rdb* rdb, PACKET* packet);
#define HANDSHAKE_DEBUG(A)
#endif // REMOTE_REMOT_PROTO_H

View File

@ -35,6 +35,7 @@
#include "../jrd/thread_proto.h"
#include "../common/config/config.h"
#include "../common/classes/init.h"
#include "../common/db_alias.h"
#include "firebird/Provider.h"
#ifdef DEV_BUILD
@ -781,9 +782,9 @@ rem_port::~rem_port()
port_events_shutdown(this);
}
delete port_srv_auth;
delete port_version;
delete port_connection;
delete port_user_name;
delete port_host;
delete port_protocol_str;
delete port_address_str;
@ -792,7 +793,7 @@ rem_port::~rem_port()
delete port_packet_vector;
#endif
delete port_auth;
delete port_crypt_keys;
#ifdef DEV_BUILD
--portCounter;
@ -873,3 +874,270 @@ Firebird::string rem_port::getRemoteId() const
return id;
}
bool REMOTE_legacy_auth(const char* nm, int p)
{
const char* legacyTrusted = "WIN_SSPI";
if (fb_utils::stricmp(legacyTrusted, nm) == 0 &&
(p == PROTOCOL_VERSION11 || p == PROTOCOL_VERSION12))
{
return true;
}
const char* legacyAuth = "LEGACY_AUTH";
if (fb_utils::stricmp(legacyAuth, nm) == 0 && p < PROTOCOL_VERSION11)
{
return true;
}
return false;
}
Firebird::PathName ClntAuthBlock::getPluginName()
{
return plugins.hasData() ? plugins.name() : "";
}
void ClntAuthBlock::extractDataFromPluginTo(Firebird::ClumpletWriter& user_id)
{
// Add user login name
if (userName.hasData())
{
user_id.insertString(CNCT_login, userName);
}
// Add plugin name
Firebird::PathName pluginName = getPluginName();
if (pluginName.hasData())
{
user_id.insertPath(CNCT_plugin_name, pluginName);
}
// Add plugin list
if (pluginList.hasData())
{
user_id.insertPath(CNCT_plugin_list, pluginList);
}
// This is specially tricky field - user_id is limited with 255 bytes per entry,
// and we have no ways to override this limit cause it can be send to any version server.
// Therefore divide data into 254-byte parts, leaving first byte for the number of that part.
// This appears more reliable than put them in strict order.
unsigned int remaining = dataFromPlugin.getCount();
UCHAR part = 0;
UCHAR buffer[255];
const UCHAR* ptr = dataFromPlugin.begin();
while (remaining > 0)
{
unsigned int step = remaining;
if (step > 254)
step = 254;
remaining -= step;
buffer[0] = part++;
fb_assert(part || remaining == 0);
memcpy(&buffer[1], ptr, step);
ptr += step;
user_id.insertBytes(CNCT_specific_data, buffer, step + 1);
}
}
void ClntAuthBlock::reset(const Firebird::PathName* fileName)
{
dataForPlugin.clear();
dataFromPlugin.clear();
authComplete = false;
firstTime = true;
pluginList = REMOTE_get_config(fileName)->getPlugins(Firebird::PluginType::AuthClient);
plugins.set(pluginList.c_str());
}
void ClntAuthBlock::storeDataForPlugin(unsigned int length, const unsigned char* data)
{
dataForPlugin.assign(data, length);
HANDSHAKE_DEBUG(fprintf(stderr, "Cln: accepted data for plugin length=%d\n", length));
}
Firebird::RefPtr<Config> REMOTE_get_config(const Firebird::PathName* dbName)
{
if (dbName)
{
Firebird::RefPtr<Config> rc;
Firebird::PathName dummy;
ResolveDatabaseAlias(*dbName, dummy, &rc);
return rc;
}
return Config::getDefaultConfig();
}
void REMOTE_parseList(Remote::ParsedList& parsed, Firebird::PathName list)
{
list.alltrim(" \t");
parsed.clear();
const char* sep = " \t,;";
for(;;)
{
Firebird::PathName::size_type p = list.find_first_of(sep);
if (p == Firebird::PathName::npos)
{
if (list.hasData())
{
parsed.push(list);
}
break;
}
parsed.push(list.substr(0, p));
list = list.substr(p);
list.ltrim(" \t,;");
}
}
void REMOTE_mergeList(Firebird::PathName& list, const Remote::ParsedList& parsed)
{
list.erase();
for (unsigned i = 0; i < parsed.getCount(); ++i)
{
if (list.hasData())
{
list += ' ';
}
list += parsed[i];
}
}
void REMOTE_check_response(Firebird::IStatus* warning, Rdb* rdb, PACKET* packet)
{
/**************************************
*
* R E M O T E _ c h e c k _ r e s p o n s e
*
**************************************
*
* Functional description
* Check response to a remote call.
*
**************************************/
// Get status vector
const ISC_STATUS success_vector[] = {isc_arg_gds, FB_SUCCESS, isc_arg_end};
const ISC_STATUS *vector = success_vector;
if (packet->p_resp.p_resp_status_vector)
{
vector = packet->p_resp.p_resp_status_vector->value();
}
// Translate any gds codes into local operating specific codes
Firebird::SimpleStatusVector newVector;
rem_port* port = rdb->rdb_port;
while (*vector != isc_arg_end)
{
const ISC_STATUS vec = *vector++;
newVector.push(vec);
switch ((USHORT) vec)
{
case isc_arg_warning:
case isc_arg_gds:
if (port->port_protocol < PROTOCOL_VERSION10)
{
fb_assert(vec == isc_arg_gds);
newVector.push(gds__encode(*vector++, 0));
}
else
newVector.push(*vector++);
break;
case isc_arg_cstring:
newVector.push(*vector++);
// fall down
default:
newVector.push(*vector++);
break;
}
}
newVector.push(isc_arg_end);
vector = newVector.begin();
const ISC_STATUS pktErr = vector[1];
if (pktErr == isc_shutdown || pktErr == isc_att_shutdown)
{
port->port_flags |= PORT_rdb_shutdown;
}
if ((packet->p_operation == op_response || packet->p_operation == op_response_piggyback) &&
!vector[1])
{
warning->set(vector);
return;
}
if (!vector[1])
{
Firebird::Arg::Gds(isc_net_read_err).raise();
}
Firebird::status_exception::raise(vector);
}
const ParametersSet dpbParam = {isc_dpb_dummy_packet_interval,
isc_dpb_user_name,
isc_dpb_auth_block,
isc_dpb_password,
isc_dpb_password_enc,
isc_dpb_trusted_auth,
isc_dpb_auth_plugin_name,
isc_dpb_auth_plugin_list,
isc_dpb_specific_auth_data,
isc_dpb_address_path,
isc_dpb_process_id,
isc_dpb_process_name,
isc_dpb_encrypt_key};
const ParametersSet spbParam = {isc_spb_dummy_packet_interval,
isc_spb_user_name,
isc_spb_auth_block,
isc_spb_password,
isc_spb_password_enc,
isc_spb_trusted_auth,
isc_spb_auth_plugin_name,
isc_spb_auth_plugin_list,
isc_spb_specific_auth_data,
isc_spb_address_path,
isc_spb_process_id,
isc_spb_process_name,
0};
const ParametersSet spbStartParam = {0,
0,
isc_spb_auth_block,
0,
0,
isc_spb_trusted_auth,
isc_spb_auth_plugin_name,
isc_spb_auth_plugin_list,
isc_spb_specific_auth_data,
0,
0,
0,
0}; // Need new parameter here
const ParametersSet spbInfoParam = {0,
0,
isc_info_svc_auth_block,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0};

View File

@ -35,14 +35,17 @@
#include "../common/ThreadData.h"
#include "../common/ThreadStart.h"
#include "../common/thd.h"
#include "../common/Auth.h"
#include "../common/classes/objects_array.h"
#include "../common/classes/fb_string.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/RefMutex.h"
#include "../common/StatusHolder.h"
#include "../common/classes/RefCounted.h"
#include "../common/classes/GetPlugins.h"
#include "firebird/Provider.h"
#include "firebird/Auth.h"
#ifndef WIN_NT
#include <signal.h>
@ -83,11 +86,10 @@ const int BLOB_LENGTH = 16384;
// fwd. decl.
namespace Firebird {
class Exception;
}
namespace Firebird {
class IEventCallback;
}
struct rem_port;
class RemCryptKey;
typedef Firebird::AutoPtr<UCHAR, Firebird::ArrayDelete<UCHAR> > UCharArrayAutoPtr;
@ -100,6 +102,20 @@ typedef Firebird::RefPtr<Firebird::IEvents> ServEvents;
typedef Firebird::RefPtr<Firebird::IService> ServService;
// this set of parameters help use same functions
// for both services and databases attachments
struct ParametersSet
{
UCHAR dummy_packet_interval, user_name, auth_block,
password, password_enc, trusted_auth,
plugin_name, plugin_list, specific_data,
address_path, process_id, process_name,
encrypt_key;
};
extern const ParametersSet dpbParam, spbParam, spbStartParam, spbInfoParam;
struct Svc : public Firebird::GlobalStorage
{
ServService svc_iface; // service interface
@ -578,9 +594,109 @@ class ServerAuthBase
{
public:
virtual ~ServerAuthBase();
virtual bool authenticate(rem_port* port, PACKET* send, const cstring* data) = 0;
virtual bool authenticate(rem_port* port, PACKET* send) = 0;
};
typedef Firebird::GetPlugins<Auth::IClient> AuthClientPlugins;
// Representation of authentication data, visible for plugin
// Transfered in format, depending upon type of the packet (phaze of handshake)
class ClntAuthBlock : public Firebird::StdPlugin<Auth::IClientBlock, FB_AUTH_CLIENT_BLOCK_VERSION>
{
private:
Firebird::PathName pluginList; // To be passed to server
Firebird::string userName, password; // Used by plugin, taken from DPB
// That two are legacy encrypted password, trusted auth data and so on - what plugin needs
Firebird::UCharBuffer dataForPlugin, dataFromPlugin;
bool hasCryptKey; // DPB contains disk crypt key, may be passed only over crypted wire
public:
AuthClientPlugins plugins;
bool authComplete; // Set as response from client that authentication accepted
bool firstTime; // Invoked first time after reset
ClntAuthBlock(const Firebird::PathName* fileName);
void storeDataForPlugin(unsigned int length, const unsigned char* data);
void resetDataFromPlugin();
void extractDataFromPluginTo(Firebird::ClumpletWriter& dpb, const ParametersSet* tags, int protocol);
void extractDataFromPluginTo(P_AUTH_CONT* to);
void load(Firebird::ClumpletReader& dpb, const ParametersSet*);
void extractDataFromPluginTo(Firebird::ClumpletWriter& user_id);
void reset(const Firebird::PathName* fileName);
bool checkPluginName(Firebird::PathName& nameToCheck);
void saveServiceDataTo(rem_port*);
void loadServiceDataFrom(rem_port*);
Firebird::PathName getPluginName();
// Auth::IClientBlock implementation
int release();
const char* FB_CARG getLogin();
const char* FB_CARG getPassword();
const unsigned char* FB_CARG getData(unsigned int* length);
void FB_CARG putData(unsigned int length, const void* data);
};
// Representation of authentication data, visible for plugin
// Transfered from client data in format, suitable for plugins access
typedef Firebird::GetPlugins<Auth::IServer> AuthServerPlugins;
class SrvAuthBlock : public Firebird::StdPlugin<Auth::IServerBlock, FB_AUTH_SERVER_BLOCK_VERSION>
{
private:
Firebird::string userName;
Firebird::PathName pluginName, pluginList;
// That two may be legacy encrypted password, trusted auth data and so on
Firebird::UCharBuffer dataForPlugin, dataFromPlugin;
Firebird::PathName dbPath;
bool flComplete, firstTime;
public:
AuthServerPlugins* plugins;
Auth::WriterImplementation authBlockWriter;
SrvAuthBlock()
: userName(getPool()), pluginName(getPool()), pluginList(getPool()),
dataForPlugin(getPool()), dataFromPlugin(getPool()),
dbPath(getPool()),
flComplete(false), firstTime(true),
plugins(NULL)
{ }
~SrvAuthBlock()
{
delete plugins;
}
void extractDataFromPluginTo(cstring* to);
void extractDataFromPluginTo(P_AUTH_CONT* to);
bool authCompleted(bool flag = false);
void setPath(const Firebird::PathName* dbPath);
void setUser(const Firebird::string& user);
const char* getPath();
void load(Firebird::ClumpletReader& userId);
const char* getPluginName();
void setPluginList(const Firebird::string& name);
const char* getPluginList();
void setPluginName(const Firebird::string& name);
void extractPluginName(cstring* to);
void setDataForPlugin(const Firebird::UCharBuffer& data);
void setDataForPlugin(const cstring& data);
void createPluginsItr();
void setDataForPlugin(const p_auth_continue* data);
void reset();
// Auth::IServerBlock implementation
int release();
const char* FB_CARG getLogin();
const unsigned char* FB_CARG getData(unsigned int* length);
void FB_CARG putData(unsigned int length, const void* data);
};
// port_flags
const USHORT PORT_symmetric = 0x0001; // Server/client architectures are symmetic
const USHORT PORT_rpc = 0x0002; // Protocol is remote procedure call
@ -669,8 +785,8 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted
rem_str* port_version;
rem_str* port_host; // Our name
rem_str* port_connection; // Name of connection
rem_str* port_user_name;
rem_str* port_passwd;
Firebird::string port_user_name;
Firebird::string port_password;
rem_str* port_protocol_str; // String containing protocol name for this port
rem_str* port_address_str; // Protocol-specific address string for the port
Rpr* port_rpr; // port stored procedure reference
@ -682,7 +798,16 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted
OBJCT port_last_object_id; // cached last id
Firebird::ObjectsArray< Firebird::Array<char> > port_queue;
size_t port_qoffset; // current packet in the queue
ServerAuthBase* port_auth;
// Authentication and crypt stuff
ServerAuthBase* port_srv_auth;
Firebird::RefPtr<SrvAuthBlock> port_srv_auth_block;
RemCryptKey* port_crypt_keys; // linked list of available wire crypt keys
bool port_need_disk_crypt; // set when appropriate DPB/SPB item is present
// requires wire crypt active before attachDatabase()
Firebird::RefPtr<Firebird::ICrypt> port_send_cipher, port_recv_cipher;
// when not NULL - used to encrypt transferred wire data and to decrypt received one
UCharArrayAutoPtr port_buffer;
public:
@ -705,11 +830,14 @@ public:
port_packet_vector(0),
#endif
port_objects(getPool()), port_version(0), port_host(0),
port_connection(0), port_user_name(0), port_passwd(0), port_protocol_str(0),
port_connection(0), port_user_name(getPool()), port_password(getPool()), port_protocol_str(0),
port_address_str(0), port_rpr(0), port_statement(0), port_receive_rmtque(0),
port_requests_queued(0), port_xcc(0), port_deferred_packets(0), port_last_object_id(0),
port_queue(getPool()), port_qoffset(0),
port_auth(0), port_buffer(FB_NEW(getPool()) UCHAR[rpt])
port_srv_auth(NULL), port_srv_auth_block(NULL),
port_crypt_keys(NULL), port_need_disk_crypt(false),
port_send_cipher(NULL), port_recv_cipher(NULL),
port_buffer(FB_NEW(getPool()) UCHAR[rpt])
{
addRef();
memset (&port_linger, 0, sizeof port_linger);
@ -899,7 +1027,6 @@ public:
};
// Queuing structure for Client batch fetches
typedef void (*t_rmtque_fn)(rem_port*, rmtque*, USHORT);
@ -949,4 +1076,45 @@ private:
Firebird::Mutex m_mutex;
};
// Element of known crypt keys list
class RemCryptKey : public Firebird::GlobalStorage
{
private:
RemCryptKey* next;
Firebird::UCharBuffer key;
Firebird::string name;
RemCryptKey(unsigned int len, const UCHAR* data, const char* nm)
: next(NULL), key(getPool()), name(getPool())
{
key.assign(data, len);
name = nm;
}
public:
void append(unsigned int len, const UCHAR* data, const char* nm)
{
if (name == nm)
return;
if (next)
next->append(len, data, nm);
else
next = new RemCryptKey(len, data, nm);
}
Firebird::UCharBuffer* choose()
{
RemCryptKey* ptr = next;
Firebird::UCharBuffer* rc = &key;
while (ptr)
{
if (ptr->key.getCount() > rc->getCount())
rc = &ptr->key;
ptr = ptr->next;
}
return rc;
}
};
#endif // REMOTE_REMOTE_H

View File

@ -91,6 +91,7 @@
#include "../common/classes/ImplementHelper.h"
#include "../auth/SecurityDatabase/LegacyServer.h"
#include "../auth/trusted/AuthSspi.h"
#include "../auth/SecureRemotePassword/server/SrpServer.h"
#ifdef UNIX
#ifdef NETBSD
@ -368,6 +369,7 @@ int CLIB_ROUTINE main( int argc, char** argv)
{ // scope for interface ptr
Firebird::PluginManagerInterfacePtr pi;
Auth::registerLegacyServer(pi);
Auth::registerSrpServer(pi);
#ifdef TRUSTED_AUTH
Auth::registerTrustedServer(pi);
#endif

View File

@ -71,7 +71,6 @@
#include "../common/classes/DbImplementation.h"
#include "../common/Auth.h"
#include "../common/classes/GetPlugins.h"
#include "../common/db_alias.h"
#include "../common/StatementMetadata.h"
#include "../common/isc_f_proto.h"
@ -105,15 +104,6 @@ public:
namespace {
// this sets of parameters help use same functions
// for both services and databases attachments
struct ParametersSet
{
UCHAR address_path;
};
const ParametersSet dpbParam = {isc_dpb_address_path};
const ParametersSet spbParam = {isc_spb_address_path};
// Disable attempts to brute-force logins/passwords
class FailedLogin
{
@ -200,7 +190,7 @@ public:
}
if (getCount() >= MAX_CONCURRENT_FAILURES)
{
// it seems we are under attack - too many wrong logins !!!
// it seems we are under attack - too many wrong logins !!
return true;
}
@ -236,48 +226,137 @@ class ServerAuth : public GlobalStorage, public ServerAuthBase
public:
virtual void accept(rem_port* port, PACKET* send, Auth::WriterImplementation* authBlock) = 0;
ServerAuth(const PathName* dbName, ClumpletWriter* aPb, const Auth::AuthTags& aTags)
: config(getConfig(dbName)),
iPb(*aPb),
authItr(PluginType::AuthServer, FB_AUTH_SERVER_VERSION, upInfo, config),
ServerAuth(const PathName* aDbName, ClumpletWriter* aPb, const ParametersSet& aTags, rem_port* port)
: authItr(NULL),
userName(getPool()),
authServer(NULL),
tags(&aTags)
tags(&aTags),
srvrBlock(port->port_srv_auth_block),
dbName(getPool())
{
if (aPb->find(isc_dpb_user_name))
if (!srvrBlock)
{
port->port_srv_auth_block = srvrBlock = new SrvAuthBlock;
}
HANDSHAKE_DEBUG(fprintf(stderr, "ServerAuth()\n"));
if (aPb->find(tags->user_name))
{
aPb->getString(userName);
userName.upper();
if (srvrBlock->getLogin() && userName != srvrBlock->getLogin())
{
(Arg::Gds(isc_login) << Arg::Gds(isc_random) << "Client error - login does not match").raise();
}
srvrBlock->setUser(userName);
HANDSHAKE_DEBUG(fprintf(stderr, "ServerAuth(): user name=%s\n", userName.c_str()));
}
const char* oldPath = srvrBlock->getPath();
if (aDbName)
{
dbName = *aDbName;
if (oldPath && (dbName != oldPath))
{
HANDSHAKE_DEBUG(fprintf(stderr, "old='%s' new='%s'\n", oldPath, dbName.c_str()));
(Arg::Gds(isc_login) << Arg::Gds(isc_random) << "Client error - database name does not match").raise();
}
srvrBlock->setPath(aDbName);
HANDSHAKE_DEBUG(fprintf(stderr, "ServerAuth(): db name=%s\n", dbName.c_str()));
}
string x;
UCharBuffer u;
if (port->port_protocol >= PROTOCOL_VERSION13)
{
if (aPb->find(tags->plugin_name))
{
aPb->getString(x);
srvrBlock->setPluginName(x);
HANDSHAKE_DEBUG(fprintf(stderr, "ServerAuth(): plugin name=%s\n", x.c_str()));
}
if (aPb->find(tags->plugin_list))
{
aPb->getString(x);
srvrBlock->setPluginList(x);
HANDSHAKE_DEBUG(fprintf(stderr, "ServerAuth(): plugin list=%s\n", x.c_str()));
}
if (aPb->find(tags->specific_data))
{
aPb->getData(u);
srvrBlock->setDataForPlugin(u);
HANDSHAKE_DEBUG(fprintf(stderr, "ServerAuth(): plugin data is %" SIZEFORMAT " len\n", u.getCount()));
}
else
{
HANDSHAKE_DEBUG(fprintf(stderr, "ServerAuth(): miss data with tag %d\n", tags->specific_data));
}
}
else if (srvrBlock->getLogin() && aPb->find(tags->password_enc))
{
srvrBlock->setPluginName("Legacy_Auth");
srvrBlock->setPluginList("Legacy_Auth");
aPb->getData(u);
srvrBlock->setDataForPlugin(u);
}
#ifdef WIN_NT
else if (aPb->find(tags->trusted_auth) && port->port_protocol >= PROTOCOL_VERSION11)
{
srvrBlock->setPluginName("Win_Sspi");
srvrBlock->setPluginList("Win_Sspi");
aPb->getData(u);
srvrBlock->setDataForPlugin(u);
}
#endif
}
~ServerAuth()
{ }
bool authenticate(rem_port* port, PACKET* send, const cstring* data)
bool authenticate(rem_port* port, PACKET* send)
{
if (srvrBlock->authCompleted())
{
accept(port, send, &srvrBlock->authBlockWriter);
return true;
}
bool working = true;
LocalStatus st;
while (working && authItr.hasData())
srvrBlock->createPluginsItr();
authItr = port->port_srv_auth_block->plugins;
if (!authItr)
{
if (port->port_protocol >= PROTOCOL_VERSION13)
{
send->p_operation = op_cont_auth;
srvrBlock->extractDataFromPluginTo(&send->p_auth_cont);
port->send(send);
memset(&send->p_auth_cont, 0, sizeof send->p_auth_cont);
return false;
}
}
while (authItr && working && authItr->hasData())
{
bool first = false;
if (! authServer)
{
authServer = authItr.plugin();
first = true;
authServer = authItr->plugin();
srvrBlock->authBlockWriter.setMethod(authItr->name());
}
fb_assert(first || data);
authBlockInterface.setMethod(authItr.name());
Auth::Result ar = first ?
authServer->startAuthentication(&st, tags, &iPb, &authBlockInterface) :
authServer->contAuthentication(&st, data->cstr_address, data->cstr_length, &authBlockInterface);
HANDSHAKE_DEBUG(fprintf(stderr, "ServerAuth calls plug %s\n", authItr->name()));
Auth::Result ar = authServer->authenticate(&st, srvrBlock, &srvrBlock->authBlockWriter);
srvrBlock->setPluginName(authItr->name());
cstring* s;
switch(ar)
{
case Auth::AUTH_MORE_DATA:
HANDSHAKE_DEBUG(fprintf(stderr, "plugin wants more data\n"));
if (port->port_protocol < PROTOCOL_VERSION11)
{
authServer = NULL;
@ -288,38 +367,18 @@ public:
if (port->port_protocol >= PROTOCOL_VERSION13)
{
send->p_operation = op_cont_auth;
s = &send->p_auth_cont.p_data;
s->cstr_allocated = 0;
// violate constness here safely - send operation does not modify data
authServer->getData(const_cast<const unsigned char**>(&s->cstr_address),
&s->cstr_length);
s = &send->p_auth_cont.p_name;
s->cstr_allocated = 0;
if (first)
{
// violate constness here safely - send operation does not modify data
s->cstr_address = (UCHAR*) authItr.name();
s->cstr_length = strlen(authItr.name());
}
else
{
s->cstr_length = 0;
}
srvrBlock->extractDataFromPluginTo(&send->p_auth_cont);
}
else
{
if (Auth::legacy(authItr.name()))
if (REMOTE_legacy_auth(authItr->name(), port->port_protocol))
{
// compatibility with FB 2.1 trusted
send->p_operation = op_trusted_auth;
s = &send->p_trau.p_trau_data;
s->cstr_allocated = 0;
// violate constness here safely - send operation does not modify data
authServer->getData(const_cast<const unsigned char**>(&s->cstr_address),
&s->cstr_length);
srvrBlock->extractDataFromPluginTo(s);
}
else
{
@ -330,21 +389,27 @@ public:
}
port->send(send);
memset(&send->p_auth_cont, 0, sizeof send->p_auth_cont);
return false;
case Auth::AUTH_CONTINUE:
authItr.next();
HANDSHAKE_DEBUG(fprintf(stderr, "Next plug suggested\n"));
authItr->next();
authServer = NULL;
continue;
case Auth::AUTH_SUCCESS:
HANDSHAKE_DEBUG(fprintf(stderr, "Ahh - success\n"));
usernameFailedLogins->loginSuccess(userName);
remoteFailedLogins->loginSuccess(port->getRemoteId());
authServer = NULL;
accept(port, send, &authBlockInterface);
srvrBlock->authCompleted(true);
accept(port, send, &srvrBlock->authBlockWriter);
return true;
case Auth::AUTH_FAILED:
HANDSHAKE_DEBUG(fprintf(stderr, "No luck today...\n"));
isc_print_status(st.get());
authServer = NULL;
working = false;
break;
@ -361,57 +426,51 @@ public:
THREAD_SLEEP(FAILURE_DELAY * 1000);
}
(Arg::Gds(isc_login) << Arg::StatusVector(st.get())).raise();
Arg::Gds loginError(isc_login);
#ifndef DEV_BUILD
if (st.get()[1] == isc_missing_data_structures)
#endif
{
loginError << Arg::StatusVector(st.get());
}
status_exception::raise(loginError.value());
return false; // compiler warning silencer
}
private:
RefPtr<Config> config;
Auth::DpbImplementation iPb;
Auth::WriterImplementation authBlockInterface;
GetPlugins<Auth::IServer> authItr;
AuthServerPlugins* authItr;
string userName;
Auth::IServer* authServer;
const Auth::AuthTags* tags;
const ParametersSet* tags;
SrvAuthBlock* srvrBlock;
RefPtr<Config> getConfig(const PathName* dbName)
{
if (dbName)
{
RefPtr<Config> config;
PathName dummy;
ResolveDatabaseAlias(*dbName, dummy, &config);
return config;
}
return Config::getDefaultConfig();
}
protected:
PathName dbName;
};
class DatabaseAuth : public ServerAuth
{
public:
DatabaseAuth(const PathName& adbName, ClumpletWriter* dpb, P_OP op)
: ServerAuth(&adbName, dpb, Auth::DB_ATTACH_LIST),
dbName(getPool(), adbName),
pb(dpb),
operation(op)
DatabaseAuth(rem_port* port, const PathName& adbName, ClumpletWriter* dpb, P_OP op)
: ServerAuth(&adbName, dpb, dpbParam, port),
operation(op),
pb(dpb)
{ }
void accept(rem_port* port, PACKET* send, Auth::WriterImplementation* authBlock);
private:
PathName dbName;
AutoPtr<ClumpletWriter> pb;
P_OP operation;
AutoPtr<ClumpletWriter> pb;
};
class ServiceAttachAuth : public ServerAuth
{
public:
ServiceAttachAuth(const PathName& pmanagerName, ClumpletWriter* spb)
: ServerAuth(NULL, spb, Auth::SVC_ATTACH_LIST),
ServiceAttachAuth(rem_port* port, const PathName& pmanagerName, ClumpletWriter* spb)
: ServerAuth(NULL, spb, spbParam, port),
managerName(getPool(), pmanagerName),
pb(spb)
{ }
@ -584,6 +643,7 @@ static void append_request_next(server_req_t*, server_req_t**);
static void attach_database(rem_port*, P_OP, P_ATCH*, PACKET*);
static void attach_service(rem_port*, P_ATCH*, PACKET*);
static void trusted_auth(rem_port*, const P_TRAU*, PACKET*);
static void continue_authentication(rem_port*, const p_auth_continue*, PACKET*);
#ifdef NOT_USED_OR_REPLACED
static void aux_connect(rem_port*, P_REQ*, PACKET*);
@ -610,6 +670,7 @@ static void release_sql_request(Rsr*);
static void release_transaction(Rtr*);
static void send_error(rem_port* port, PACKET* apacket, ISC_STATUS errcode);
static void send_error(rem_port* port, PACKET* apacket, const Firebird::Arg::StatusVector&);
static void set_server(rem_port*, USHORT);
static int shut_server(const int, const int, void*);
static THREAD_ENTRY_DECLARE loopThread(THREAD_ENTRY_PARAM);
@ -1248,7 +1309,6 @@ static bool accept_connection(rem_port* port, P_CNCT* connect, PACKET* send)
// Accept the physical connection
send->p_operation = op_reject;
P_ACPT* accept = &send->p_acpt;
if (!port->accept(connect))
{
@ -1256,7 +1316,6 @@ static bool accept_connection(rem_port* port, P_CNCT* connect, PACKET* send)
return false;
}
// Select the most appropriate protocol (this will get smarter)
P_ARCH architecture = arch_generic;
USHORT version = 0;
@ -1288,19 +1347,106 @@ static bool accept_connection(rem_port* port, P_CNCT* connect, PACKET* send)
version = protocol->p_cnct_version;
architecture = protocol->p_cnct_architecture;
type = MIN(protocol->p_cnct_max_type, ptype_lazy_send);
send->p_operation = op_accept;
}
}
HANDSHAKE_DEBUG(fprintf(stderr, "protoaccept a=%d (v>=13)=%d %d %d\n",
accepted, version >= PROTOCOL_VERSION13, version, PROTOCOL_VERSION13));
// We are going to try authentication handshake
LocalStatus status;
P_ACPT* accept = &send->p_acpt;
bool returnData = false;
if (accepted && version >= PROTOCOL_VERSION13)
{
HANDSHAKE_DEBUG(fprintf(stderr, "accept connection creates port_srv_auth_block\n"));
port->port_srv_auth_block = new SrvAuthBlock;
send->p_acpd.p_acpt_authenticated = 0;
Firebird::ClumpletReader id(Firebird::ClumpletReader::UnTagged,
connect->p_cnct_user_id.cstr_address,
connect->p_cnct_user_id.cstr_length);
HANDSHAKE_DEBUG(fprintf(stderr, "accept connection is going to load data to port_srv_auth_block\n"));
port->port_srv_auth_block->load(id);
if (port->port_srv_auth_block->getLogin())
{
port->port_user_name = port->port_srv_auth_block->getLogin();
}
HANDSHAKE_DEBUG(fprintf(stderr, "accept connection finished with port_srv_auth_block prepare, a=%d\n", accepted));
if (port->port_srv_auth_block->getPluginName())
{
accept = &send->p_acpd;
Firebird::PathName file(connect->p_cnct_file.cstr_address, connect->p_cnct_file.cstr_length);
port->port_srv_auth_block->setPath(&file);
HANDSHAKE_DEBUG(fprintf(stderr, "accept connection calls createPluginsItr\n"));
port->port_srv_auth_block->createPluginsItr();
if (port->port_srv_auth_block->plugins) // We have all required data and iterator was created
{
HANDSHAKE_DEBUG(fprintf(stderr, "call plugin %s\n", port->port_srv_auth_block->getPluginName()));
AuthServerPlugins* plugins = port->port_srv_auth_block->plugins;
for (; plugins->hasData(); plugins->next())
{
port->port_srv_auth_block->authBlockWriter.setMethod(plugins->name());
switch (port->port_srv_auth_block->plugins->plugin()->
authenticate(&status, port->port_srv_auth_block,
&port->port_srv_auth_block->authBlockWriter))
{
case Auth::AUTH_SUCCESS:
port->port_srv_auth_block->authCompleted(true);
send->p_acpd.p_acpt_authenticated = 1;
break;
case Auth::AUTH_FAILED:
{
Arg::Gds loginError(isc_login);
#ifndef DEV_BUILD
if (status.get()[1] == isc_missing_data_structures)
#endif
{
loginError << Arg::StatusVector(status.get());
}
status.set(loginError.value());
}
accepted = false;
break;
case Auth::AUTH_CONTINUE:
// try next plugin
continue;
case Auth::AUTH_MORE_DATA:
port->port_srv_auth_block->extractDataFromPluginTo(&send->p_acpd.p_acpt_data);
port->port_srv_auth_block->extractPluginName(&send->p_acpd.p_acpt_plugin);
returnData = true;
break;
}
break;
}
if (!plugins->hasData())
{
accepted = false;
}
}
}
}
// Send off out gracious acceptance or flag rejection
if (!accepted)
{
port->send(send);
if (!status.isSuccess())
port->send_response(send, 0, 0, status.get(), false);
else
port->send(send);
return false;
}
accept->p_acpt_version = port->port_protocol = version;
accept->p_acpt_architecture = architecture;
accept->p_acpt_type = type;
send->p_operation = returnData ? op_accept_data : op_accept;
HANDSHAKE_DEBUG(fprintf(stderr, "accepted ud=%d v=%x\n", returnData, version));
// and modify the version string to reflect the chosen protocol
@ -1502,13 +1648,13 @@ static void attach_database(rem_port* port, P_OP operation, P_ATCH* attach, PACK
ClumpletReader::dpbList, MAX_DPB_SIZE, attach->p_atch_dpb.cstr_address,
attach->p_atch_dpb.cstr_length);
port->port_auth = new DatabaseAuth(PathName(attach->p_atch_file.cstr_address,
port->port_srv_auth = new DatabaseAuth(port, PathName(attach->p_atch_file.cstr_address,
attach->p_atch_file.cstr_length), wrt, operation);
if (port->port_auth->authenticate(port, send, NULL))
if (port->port_srv_auth->authenticate(port, send))
{
delete port->port_auth;
port->port_auth = NULL;
delete port->port_srv_auth;
port->port_srv_auth = NULL;
}
}
@ -2082,22 +2228,6 @@ void rem_port::disconnect(PACKET* sendL, PACKET* receiveL)
delete this->port_version;
this->port_version = NULL;
}
if (this->port_passwd)
{
#ifdef DEBUG_REMOTE_MEMORY
printf("disconnect(server) free string %x\n", this->port_passwd);
#endif
delete this->port_passwd;
this->port_passwd = NULL;
}
if (this->port_user_name)
{
#ifdef DEBUG_REMOTE_MEMORY
printf("disconnect(server) free string %x\n", this->port_user_name);
#endif
delete this->port_user_name;
this->port_user_name = NULL;
}
if (this->port_host)
{
#ifdef DEBUG_REMOTE_MEMORY
@ -3071,11 +3201,11 @@ ISC_STATUS rem_port::get_slice(P_SLC * stuff, PACKET* sendL)
class ServiceQueryAuth : public ServerAuth
{
public:
ServiceQueryAuth(OBJCT pinfoObject, ClumpletWriter* spb,
ServiceQueryAuth(rem_port* port, OBJCT pinfoObject, ClumpletWriter* spb,
unsigned int pSendLength, const UCHAR* pSendItems,
unsigned int pReceiveLength, const UCHAR* pReceiveItems,
unsigned int pBufferLength)
: ServerAuth(NULL, spb, Auth::SVC_QUERY_LIST),
: ServerAuth(NULL, spb, spbInfoParam, port),
pb(spb),
sendItems(getPool(), ClumpletReader::SpbSendItems, MAX_DPB_SIZE, pSendItems, pSendLength, 0),
receiveItems(getPool()),
@ -3255,17 +3385,24 @@ void rem_port::info(P_OP op, P_INFO* stuff, PACKET* sendL)
FB_NEW(*getDefaultMemoryPool()) ClumpletWriter(*getDefaultMemoryPool(),
ClumpletReader::WideUnTagged, MAX_DPB_SIZE);
delete port_auth;
///port_auth = NULL;
port_auth = new ServiceQueryAuth(stuff->p_info_object, wrt,
if (port_srv_auth_block)
{
port_srv_auth_block->reset();
}
delete port_srv_auth;
// port_srv_auth = NULL;
port_srv_auth = new ServiceQueryAuth(this, stuff->p_info_object, wrt,
stuff->p_info_items.cstr_length, stuff->p_info_items.cstr_address,
info_len, info_buffer, stuff->p_info_buffer_length);
if (port_auth->authenticate(this, sendL, NULL))
if (port_user_name.hasData())
{
delete port_auth;
port_auth = NULL;
port_srv_auth_block->setUser(port_user_name);
}
if (port_srv_auth->authenticate(this, sendL))
{
delete port_srv_auth;
port_srv_auth = NULL;
}
return;
}
@ -3638,11 +3775,10 @@ static bool process_packet(rem_port* port, PACKET* sendL, PACKET* receive, rem_p
case op_connect:
if (!accept_connection(port, &receive->p_cnct, sendL))
{
rem_str* string = port->port_user_name;
if (string)
const string& s = port->port_user_name;
if (s.hasData())
{
gds__log("SERVER/process_packet: connection rejected for %*.*s",
string->str_length, string->str_length, string->str_data);
gds__log("SERVER/process_packet: connection rejected for %s", s.c_str());
}
if (port->port_server->srvr_flags & SRVR_multi_client) {
port->port_state = rem_port::BROKEN;
@ -3669,10 +3805,14 @@ static bool process_packet(rem_port* port, PACKET* sendL, PACKET* receive, rem_p
attach_service(port, &receive->p_atch, sendL);
break;
case op_trusted_auth:
case op_trusted_auth: // PROTOCOL < 13
trusted_auth(port, &receive->p_trau, sendL);
break;
case op_cont_auth: // PROTOCOL >= 13
continue_authentication(port, &receive->p_auth_cont, sendL);
break;
case op_update_account_info:
case op_authenticate_user:
send_error(port, sendL, isc_wish_list);
@ -3937,16 +4077,56 @@ static void trusted_auth(rem_port* port, const P_TRAU* p_trau, PACKET* send)
* Server side of trusted auth handshake.
*
**************************************/
ServerAuthBase* sa = port->port_auth;
ServerAuthBase* sa = port->port_srv_auth;
if (! sa)
{
send_error(port, send, isc_unavailable);
}
if (sa->authenticate(port, send, &p_trau->p_trau_data))
if (port->port_protocol < PROTOCOL_VERSION11 || port->port_protocol >= PROTOCOL_VERSION13)
{
send_error(port, send, (Arg::Gds(isc_random) << "Operation not supported for network protocol"));
}
HANDSHAKE_DEBUG(fprintf(stderr, "trusted_auth\n"));
port->port_srv_auth_block->setDataForPlugin(p_trau->p_trau_data);
if (sa->authenticate(port, send))
{
delete sa;
port->port_auth = NULL;
port->port_srv_auth = NULL;
}
}
static void continue_authentication(rem_port* port, const p_auth_continue* p_auth_c, PACKET* send)
{
/**************************************
*
* c o n t i n u e _ a u t h e n t i c a t i o n
*
**************************************
*
* Functional description
* Server side of multi-hop auth handshake.
*
**************************************/
ServerAuthBase* sa = port->port_srv_auth;
if (! sa)
{
send_error(port, send, isc_unavailable);
}
if (port->port_protocol < PROTOCOL_VERSION13)
{
send_error(port, send, (Arg::Gds(isc_random) << "Operation not supported for network protocol"));
}
HANDSHAKE_DEBUG(fprintf(stderr, "continue_authentication\n"));
port->port_srv_auth_block->setDataForPlugin(p_auth_c);
if (sa->authenticate(port, send))
{
delete sa;
port->port_srv_auth = NULL;
}
}
@ -4671,6 +4851,14 @@ static void send_error(rem_port* port, PACKET* apacket, ISC_STATUS errcode)
port->send_response(apacket, 0, 0, &status_vector, false);
}
// Maybe this can be a member of rem_port?
static void send_error(rem_port* port, PACKET* apacket, const Firebird::Arg::StatusVector& err)
{
LocalStatus status_vector;
err.copyTo(&status_vector);
port->send_response(apacket, 0, 0, &status_vector, false);
}
static void attach_service(rem_port* port, P_ATCH* attach, PACKET* sendL)
{
@ -4682,13 +4870,13 @@ static void attach_service(rem_port* port, P_ATCH* attach, PACKET* sendL)
// Check credentials in default way right now
ClumpletWriter* wrt = FB_NEW(*getDefaultMemoryPool()) ClumpletWriter(*getDefaultMemoryPool(),
ClumpletReader::spbList, MAX_DPB_SIZE, attach->p_atch_dpb.cstr_address, attach->p_atch_dpb.cstr_length);
port->port_auth = new ServiceAttachAuth(PathName(attach->p_atch_file.cstr_address,
port->port_srv_auth = new ServiceAttachAuth(port, PathName(attach->p_atch_file.cstr_address,
attach->p_atch_file.cstr_length), wrt);
if (port->port_auth->authenticate(port, sendL, NULL))
if (port->port_srv_auth->authenticate(port, sendL))
{
delete port->port_auth;
port->port_auth = NULL;
delete port->port_srv_auth;
port->port_srv_auth = NULL;
}
}
else
@ -4696,6 +4884,11 @@ static void attach_service(rem_port* port, P_ATCH* attach, PACKET* sendL)
// Delay authentication till service start/info request
ClumpletWriter spb(ClumpletReader::spbList, MAX_DPB_SIZE,
attach->p_atch_dpb.cstr_address, attach->p_atch_dpb.cstr_length);
if (spb.find(isc_spb_user_name))
{
spb.getString(port->port_user_name);
port->port_user_name.upper();
}
port->service_attach(manager.c_str(), &spb, sendL, false);
}
}
@ -4831,8 +5024,8 @@ ISC_STATUS rem_port::service_end(P_RLSE* /*release*/, PACKET* sendL)
class ServiceStartAuth : public ServerAuth
{
public:
ServiceStartAuth(PathName& dbName, ClumpletWriter* authSpb, ClumpletWriter* origSpb)
: ServerAuth(dbName.hasData() ? &dbName : NULL, authSpb, Auth::SVC_START_LIST),
ServiceStartAuth(rem_port* port, PathName& dbName, ClumpletWriter* authSpb, ClumpletWriter* origSpb)
: ServerAuth(dbName.hasData() ? &dbName : NULL, authSpb, spbStartParam, port),
authPb(authSpb), startPb(origSpb)
{ }
@ -4912,8 +5105,10 @@ void rem_port::service_start(P_INFO * stuff, PACKET* sendL)
case isc_spb_dbname:
spb->getPath(dbName);
break;
case isc_spb_trusted_auth:
authParams->insertBytes(isc_spb_trusted_auth, spb->getBytes(), spb->getClumpLength());
case isc_spb_specific_auth_data:
case isc_spb_auth_plugin_list:
case isc_spb_auth_plugin_name:
authParams->insertBytes(spb->getClumpTag(), spb->getBytes(), spb->getClumpLength());
spb->deleteClumplet();
fDel = true;
break;
@ -4924,14 +5119,22 @@ void rem_port::service_start(P_INFO * stuff, PACKET* sendL)
}
}
delete port_auth;
///port_auth = NULL;
port_auth = new ServiceStartAuth(dbName, authParams, spb);
if (port_auth->authenticate(this, sendL, NULL))
if (port_srv_auth_block)
{
delete port_auth;
port_auth = NULL;
port_srv_auth_block->reset();
}
delete port_srv_auth;
///port_srv_auth = NULL;
port_srv_auth = new ServiceStartAuth(this, dbName, authParams, spb);
if (port_user_name.hasData())
{
port_srv_auth_block->setUser(port_user_name);
}
if (port_srv_auth->authenticate(this, sendL))
{
delete port_srv_auth;
port_srv_auth = NULL;
}
}
}
@ -5666,3 +5869,258 @@ static int shut_server(const int, const int, void*)
server_shutdown = true;
return 0;
}
void SrvAuthBlock::extractDataFromPluginTo(cstring* to)
{
to->cstr_allocated = 0;
to->cstr_length = dataFromPlugin.getCount();
to->cstr_address = dataFromPlugin.begin();
}
bool SrvAuthBlock::authCompleted(bool flag)
{
if (flag)
flComplete = true;
return flComplete;
}
void SrvAuthBlock::setPath(const Firebird::PathName* aDbPath)
{
if (aDbPath)
dbPath = *aDbPath;
else
dbPath = "";
}
void SrvAuthBlock::setUser(const Firebird::string& user)
{
userName = user;
}
const char* SrvAuthBlock::getPath()
{
return dbPath.nullStr();
}
void SrvAuthBlock::load(Firebird::ClumpletReader& id)
{
// This array is needed only to make sure that all parts of specific data is present
UCHAR checkBytes[256];
memset(checkBytes, 0, sizeof(checkBytes));
UCHAR top = 0;
for (id.rewind(); !id.isEof(); id.moveNext())
{
switch (id.getClumpTag())
{
case CNCT_login:
id.getString(userName);
userName.upper();
HANDSHAKE_DEBUG(fprintf(stderr, "login %s\n", userName.c_str()));
break;
case CNCT_plugin_name:
id.getPath(pluginName);
firstTime = false;
HANDSHAKE_DEBUG(fprintf(stderr, "plugin %s\n", pluginName.c_str()));
break;
case CNCT_plugin_list:
id.getPath(pluginList);
HANDSHAKE_DEBUG(fprintf(stderr, "plugin list %s\n", pluginList.c_str()));
break;
case CNCT_specific_data:
{
string tmp;
const UCHAR* specData = id.getBytes();
size_t len = id.getClumpLength();
if (len > 1)
{
--len;
unsigned offset = specData[0];
if (offset + 1 > top)
top = offset + 1;
checkBytes[offset] = 1;
offset *= 254;
++specData;
dataForPlugin.grow(offset + len);
memcpy(&dataForPlugin[offset], specData, len);
}
}
break;
}
}
for (UCHAR segment = 0; segment < top; ++segment)
{
if (!checkBytes[segment])
{
(Arg::Gds(isc_random) << "Missing segment in specific data").raise();
}
}
HANDSHAKE_DEBUG(fprintf(stderr, "data %" SIZEFORMAT "\n", dataForPlugin.getCount()));
}
const char* SrvAuthBlock::getPluginName()
{
return pluginName.nullStr();
}
void SrvAuthBlock::setPluginName(const Firebird::string& name)
{
pluginName = name.ToPathName();
}
void SrvAuthBlock::setPluginList(const Firebird::string& list)
{
if (firstTime)
{
pluginList = list.ToPathName();
}
if (pluginList.hasData())
{
firstTime = false;
}
}
void SrvAuthBlock::setDataForPlugin(const Firebird::UCharBuffer& data)
{
dataForPlugin.assign(data.begin(), data.getCount());
}
void SrvAuthBlock::setDataForPlugin(const cstring& data)
{
dataForPlugin.assign(data.cstr_address, data.cstr_length);
}
void SrvAuthBlock::setDataForPlugin(const p_auth_continue* data)
{
dataForPlugin.assign(data->p_data.cstr_address, data->p_data.cstr_length);
HANDSHAKE_DEBUG(fprintf(stderr, "setDataForPlugin=%d firstTime = %d nm=%d ls=%d login='%s'\n",
data->p_data.cstr_length, firstTime, data->p_name.cstr_length,
data->p_list.cstr_length, userName.c_str()));
if (firstTime)
{
pluginName.assign(data->p_name.cstr_address, data->p_name.cstr_length);
pluginList.assign(data->p_list.cstr_address, data->p_list.cstr_length);
firstTime = false;
}
}
void SrvAuthBlock::extractDataFromPluginTo(P_AUTH_CONT* to)
{
to->p_data.cstr_length = dataFromPlugin.getCount();
to->p_data.cstr_address = dataFromPlugin.begin();
to->p_data.cstr_allocated = 0;
extractPluginName(&to->p_name);
}
void SrvAuthBlock::extractPluginName(cstring* to)
{
to->cstr_length = pluginName.length();
to->cstr_address = (UCHAR*)(pluginName.c_str());
to->cstr_allocated = 0;
}
int SrvAuthBlock::release()
{
if (--refCounter != 0)
return 1;
delete this;
return 0;
}
const char* SrvAuthBlock::getLogin()
{
return userName.nullStr();
}
const unsigned char* SrvAuthBlock::getData(unsigned int* length)
{
*length = dataForPlugin.getCount();
return (*length) ? dataForPlugin.begin() : NULL;
}
void SrvAuthBlock::putData(unsigned int length, const void* data)
{
memcpy(dataFromPlugin.getBuffer(length), data, length);
}
void SrvAuthBlock::createPluginsItr()
{
if (firstTime || plugins)
{
return;
}
Remote::ParsedList fromClient;
REMOTE_parseList(fromClient, pluginList);
RefPtr<Config> myConfig = REMOTE_get_config(dbPath.hasData() ? &dbPath : NULL);
Remote::ParsedList onServer;
REMOTE_parseList(onServer, myConfig->getPlugins(PluginType::AuthServer));
Remote::ParsedList final;
for (unsigned s = 0; s < onServer.getCount(); ++s)
{
// do not expect too long lists, therefore use double loop
for (unsigned c = 0; c < fromClient.getCount(); ++c)
{
if (onServer[s] == fromClient[c])
{
final.push(onServer[s]);
}
}
}
if (final.getCount() == 0)
{
HANDSHAKE_DEBUG(fprintf(stderr, "No matching plugins on server\n"));
(Arg::Gds(isc_login)
#ifdef DEV_BUILD
<< Arg::Gds(isc_random) << "No matching plugins on server"
#endif
).raise();
}
// reorder to make it match first, already passed, plugin data
for (unsigned f = 1; f < final.getCount(); ++f)
{
if (final[f] == pluginName)
{
final[f] = final[0];
final[0] = pluginName;
break;
}
}
// special case - last plugin from the list on the server may be used to check
// correctness of what previous one added to auth parameters block
if (final[final.getCount() - 1] != onServer[onServer.getCount() - 1])
{
final.push(onServer[onServer.getCount() - 1]);
}
REMOTE_mergeList(pluginList, final);
plugins = new AuthServerPlugins(PluginType::AuthServer, FB_AUTH_SERVER_VERSION, upInfo,
myConfig, pluginList.c_str());
}
void SrvAuthBlock::reset()
{
pluginName = "";
pluginList = "";
dataForPlugin.clear();
dataFromPlugin.clear();
flComplete = false;
firstTime = true;
authBlockWriter.reset();
delete plugins;
plugins = NULL;
}

View File

@ -248,14 +248,6 @@ int gsec(Firebird::UtilSvc* uSvc)
uSvc->checkService();
Auth::Get getPlugin(pseudoConfig);
manager = getPlugin.plugin();
if (!manager)
{
GSEC_error_redirect((Firebird::Arg::Gds(isc_random) << "Missing management plugin").value(), GsecMsg15);
}
manager->addRef();
fb_assert(user_data->trustedUser.entered() || user_data->authenticationBlock.hasData());
if (user_data->trustedUser.entered() || user_data->authenticationBlock.hasData())
{
@ -314,10 +306,25 @@ int gsec(Firebird::UtilSvc* uSvc)
};
Firebird::LocalStatus st;
GsecInfo info(user_data->trustedUser.get(), user_data->role.get(),
user_data->trustedRole && !user_data->role.entered(),
network_protocol.c_str(), remote_address.c_str(), &user_data->authenticationBlock);
manager->start(&st, &info);
try
{
Auth::Get getPlugin(pseudoConfig);
manager = getPlugin.plugin();
if (!manager)
{
GSEC_error_redirect((Firebird::Arg::Gds(isc_random) << "Missing management plugin").value(), GsecMsg15);
}
manager->addRef();
GsecInfo info(user_data->trustedUser.get(), user_data->role.get(),
user_data->trustedRole && !user_data->role.entered(),
network_protocol.c_str(), remote_address.c_str(), &user_data->authenticationBlock);
manager->start(&st, &info);
}
catch (const Firebird::Exception& ex)
{
ex.stuffException(&st);
}
if (!st.isSuccess())
{
@ -481,7 +488,6 @@ int gsec(Firebird::UtilSvc* uSvc)
user_data->database.setEntered(databaseNameEntered);
user_data->role.set(sqlRoleName.c_str());
user_data->role.setEntered(sqlRoleName.hasData());
user_data->role.setSpecified(user_data->role.entered());
if (ret == 0)
{
@ -1380,8 +1386,16 @@ void GSEC_error_redirect(const ISC_STATUS* status_vector, USHORT errcode)
*
**************************************/
GSEC_print_status(status_vector);
GSEC_error(errcode);
tsec* tdsec = tsec::getSpecific();
if (!tdsec->utilSvc->isService())
{
GSEC_print_status(status_vector);
GSEC_error(errcode);
}
else
{
GSEC_error(errcode, status_vector);
}
}
void GSEC_diag(USHORT errcode)
@ -1403,7 +1417,7 @@ void GSEC_diag(USHORT errcode)
GSEC_print(errcode);
}
void GSEC_error(USHORT errcode)
void GSEC_error(USHORT errcode, const ISC_STATUS* status_vector)
{
/**************************************
*
@ -1419,6 +1433,10 @@ void GSEC_error(USHORT errcode)
tsec* tdsec = tsec::getSpecific();
tdsec->utilSvc->setServiceStatus(GSEC_MSG_FAC, errcode, dummy);
if (status_vector)
{
tdsec->utilSvc->setServiceStatus(status_vector);
}
tdsec->utilSvc->started();
GSEC_print(errcode);

View File

@ -7,7 +7,7 @@
// Output reporting utilities
void GSEC_print_status(const ISC_STATUS*);
void GSEC_error_redirect(const ISC_STATUS*, USHORT);
void GSEC_error(USHORT);
void GSEC_error(USHORT code, const ISC_STATUS* status = NULL);
void GSEC_exit();
void GSEC_print(USHORT, const char* str = NULL);
void GSEC_message(USHORT, const char* str = NULL);

View File

@ -51,7 +51,6 @@
#include "../yvalve/gds_proto.h"
#include "../common/isc_f_proto.h"
#include "../common/thd.h"
#include "../common/enc_proto.h"
#include "../common/utils_proto.h"
#include "../common/classes/ClumpletWriter.h"
#include "../jrd/constants.h"

View File

@ -37,7 +37,6 @@
#include "../jrd/inf_pub.h"
#include "../common/isc_proto.h"
#include "../jrd/acl.h"
///#include "../common/classes/init.h"
using namespace Firebird;
using namespace Why;

View File

@ -904,15 +904,23 @@ void FB_CARG PluginManager::unregisterModule(IPluginModule* cleanup)
fb_shutdown(5000, fb_shutrsn_exit_called);
}
IPluginSet* FB_CARG PluginManager::getPlugins(unsigned int interfaceType, const char* namesList,
IPluginSet* FB_CARG PluginManager::getPlugins(IStatus* status, unsigned int interfaceType, const char* namesList,
int desiredVersion, UpgradeInfo* ui,
IFirebirdConf* firebirdConf)
{
MutexLockGuard g(plugins->mutex);
try
{
MutexLockGuard g(plugins->mutex);
IPluginSet* rc = new PluginSet(interfaceType, namesList, desiredVersion, ui, firebirdConf);
rc->addRef();
return rc;
IPluginSet* rc = new PluginSet(interfaceType, namesList, desiredVersion, ui, firebirdConf);
rc->addRef();
return rc;
}
catch (const Exception& ex)
{
ex.stuffException(status);
return NULL;
}
}

View File

@ -42,11 +42,11 @@ class PluginManager : public AutoIface<IPluginManager, FB_PLUGIN_MANAGER_VERSION
{
public:
// IPluginManager implementation
IPluginSet* FB_CARG getPlugins(unsigned int interfaceType, const char* namesList,
int desiredVersion, UpgradeInfo* ui,
IFirebirdConf* firebirdConf);
IPluginSet* FB_CARG getPlugins(IStatus* status, unsigned int interfaceType,
const char* namesList, int desiredVersion, UpgradeInfo* ui,
IFirebirdConf* firebirdConf);
void FB_CARG registerPluginFactory(unsigned int interfaceType, const char* defaultName,
IPluginFactory* factory);
IPluginFactory* factory);
IConfig* FB_CARG getConfig(const char* filename);
void FB_CARG releasePlugin(IPluginBase* plugin);
void FB_CARG registerModule(IPluginModule* module);

View File

@ -5076,7 +5076,7 @@ YService* Dispatcher::attachServiceManager(IStatus* status, const char* serviceN
PathName svcName(serviceName);
svcName.trim();
ClumpletReader spbReader(ClumpletReader::SpbAttach, spb, spbLength);
ClumpletReader spbReader(ClumpletReader::spbList, spb, spbLength);
if ((spbReader.find(isc_spb_auth_block) && spbReader.getClumpLength() > 0) ||
ISC_check_if_remote(svcName, false))
{