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:
parent
c2e17f5cbf
commit
7fb8ebd3a9
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
35
configure.in
35
configure.in
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
212
src/auth/SecureRemotePassword/BigInteger.cpp
Normal file
212
src/auth/SecureRemotePassword/BigInteger.cpp
Normal 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
|
80
src/auth/SecureRemotePassword/BigInteger.h
Normal file
80
src/auth/SecureRemotePassword/BigInteger.h
Normal 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
|
157
src/auth/SecureRemotePassword/Message.h
Normal file
157
src/auth/SecureRemotePassword/Message.h
Normal 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;
|
||||
}
|
||||
};
|
173
src/auth/SecureRemotePassword/client/SrpClient.cpp
Normal file
173
src/auth/SecureRemotePassword/client/SrpClient.cpp
Normal 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
|
||||
|
38
src/auth/SecureRemotePassword/client/SrpClient.h
Normal file
38
src/auth/SecureRemotePassword/client/SrpClient.h
Normal 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
|
633
src/auth/SecureRemotePassword/manage/SrpManagement.cpp
Normal file
633
src/auth/SecureRemotePassword/manage/SrpManagement.cpp
Normal 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();
|
||||
}
|
48
src/auth/SecureRemotePassword/misc/prime.cpp
Normal file
48
src/auth/SecureRemotePassword/misc/prime.cpp
Normal 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);
|
||||
}
|
13
src/auth/SecureRemotePassword/misc/test.sh
Executable file
13
src/auth/SecureRemotePassword/misc/test.sh
Executable 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
|
44
src/auth/SecureRemotePassword/misc/test_srp.cpp
Normal file
44
src/auth/SecureRemotePassword/misc/test_srp.cpp
Normal 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");
|
||||
}
|
321
src/auth/SecureRemotePassword/server/SrpServer.cpp
Normal file
321
src/auth/SecureRemotePassword/server/SrpServer.cpp
Normal 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
|
||||
|
38
src/auth/SecureRemotePassword/server/SrpServer.h
Normal file
38
src/auth/SecureRemotePassword/server/SrpServer.h
Normal 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
|
221
src/auth/SecureRemotePassword/srp.cpp
Normal file
221
src/auth/SecureRemotePassword/srp.cpp
Normal 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
|
||||
|
126
src/auth/SecureRemotePassword/srp.h
Normal file
126
src/auth/SecureRemotePassword/srp.h
Normal 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
|
@ -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()
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -28,7 +28,7 @@
|
||||
#define AUTH_LEGACY_MANAGEMENT_H
|
||||
|
||||
#include "../common/classes/ImplementHelper.h"
|
||||
#include "../auth/AuthInterface.h"
|
||||
#include "firebird/Auth.h"
|
||||
|
||||
|
||||
namespace Auth {
|
||||
|
@ -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()
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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},
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 *
|
||||
*****************************/
|
||||
|
@ -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
|
||||
{
|
@ -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
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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},
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user