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

Fix found by Jim Starkey man-in-themiddle attack on ATTACH packet.

That packet may contain database name, command line for service and/or some other important and critical information.
To avoid such attack wire encryption is started before attaching database or service manager, right after connect.
Also should fix a number of issues found in Alpha1 regarding services attach.
This commit is contained in:
alexpeshkoff 2013-10-16 12:53:04 +00:00
parent 61d5a49c93
commit 5a054cca16
47 changed files with 998 additions and 1095 deletions

View File

@ -191,3 +191,35 @@ value from isc_service_query().
A sample of how services API should be used for remote backup and restore can be
found in source code of fbsvcmgr.
5) Services API extension - using services with non-default security database.
(Alex Peshkov, peshkoff@mail.ru, 2013)
If one wants to use services API to access database which is configured to use
non-default security database new SPB item isc_spb_expected_db should be used
when attaching to services manager. Value of this item is a database which is
expected to be accessed.
Formally this does not raise backward incompatibility - as long as one does not
use new FB3 feature (multiple security databases) he has no problems with old
programs using services API. In a case when one has really big need to use old
program for a database with non-default configuration there is a workaround:
setting environment variable FB_EXPECTED_DB which will be added to SPB
automatically.
Example. Imagine we have the following lines in databases.conf:
employee = $(dir_sampledb)/employee.fdb
{
SecurityDatabase = employee
}
i.e. employee database is configured as security database for itself.
To access it using fbsvcmgr one should use the following command line:
fbsvcmgr host:service_mgr user sysdba password xxx expected_db employee action_db_stats dbname employee sts_data_pages
or in advance set FB_EXPECTED_DB:
export FB_EXPECTED_DB=employee
fbsvcmgr host:service_mgr user sysdba password xxx action_db_stats dbname employee sts_data_pages
Certainly any other database action can be used here.

View File

@ -1530,6 +1530,28 @@ C --
PARAMETER (GDS__protect_ownership = 335545058)
INTEGER*4 GDS__badvarnum
PARAMETER (GDS__badvarnum = 335545059)
INTEGER*4 GDS__sec_context
PARAMETER (GDS__sec_context = 335545060)
INTEGER*4 GDS__multi_segment
PARAMETER (GDS__multi_segment = 335545061)
INTEGER*4 GDS__login_changed
PARAMETER (GDS__login_changed = 335545062)
INTEGER*4 GDS__auth_handshake_limit
PARAMETER (GDS__auth_handshake_limit = 335545063)
INTEGER*4 GDS__wirecrypt_incompatible
PARAMETER (GDS__wirecrypt_incompatible = 335545064)
INTEGER*4 GDS__miss_wirecrypt
PARAMETER (GDS__miss_wirecrypt = 335545065)
INTEGER*4 GDS__wirecrypt_key
PARAMETER (GDS__wirecrypt_key = 335545066)
INTEGER*4 GDS__wirecrypt_plugin
PARAMETER (GDS__wirecrypt_plugin = 335545067)
INTEGER*4 GDS__secdb_name
PARAMETER (GDS__secdb_name = 335545068)
INTEGER*4 GDS__auth_data
PARAMETER (GDS__auth_data = 335545069)
INTEGER*4 GDS__auth_datalength
PARAMETER (GDS__auth_datalength = 335545070)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -772,6 +772,17 @@ const
gds_include_miss = 335545057;
gds_protect_ownership = 335545058;
gds_badvarnum = 335545059;
gds_sec_context = 335545060;
gds_multi_segment = 335545061;
gds_login_changed = 335545062;
gds_auth_handshake_limit = 335545063;
gds_wirecrypt_incompatible = 335545064;
gds_miss_wirecrypt = 335545065;
gds_wirecrypt_key = 335545066;
gds_wirecrypt_plugin = 335545067;
gds_secdb_name = 335545068;
gds_auth_data = 335545069;
gds_auth_datalength = 335545070;
gds_gfix_db_name = 335740929;
gds_gfix_invalid_sw = 335740930;
gds_gfix_incmp_sw = 335740932;

View File

@ -79,17 +79,18 @@ int SrpClient::authenticate(IStatus* status, IClientBlock* cb)
}
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: SRP phase2\n"));
unsigned int length;
unsigned length;
const unsigned char* saltAndKey = cb->getData(&length);
if (!saltAndKey || length == 0)
{
(Arg::Gds(isc_random) << "Missing data from server").raise();
Arg::Gds(isc_auth_data).raise();
}
if (length > (RemotePassword::SRP_SALT_SIZE + RemotePassword::SRP_KEY_SIZE + 2) * 2)
const unsigned expectedLength =
(RemotePassword::SRP_SALT_SIZE + RemotePassword::SRP_KEY_SIZE + 2) * 2;
if (length > expectedLength)
{
string msg;
msg.printf("Wrong length (%d) of data from server", length);
(Arg::Gds(isc_random) << msg).raise();
(Arg::Gds(isc_auth_datalength) << Arg::Num(length) <<
Arg::Num(expectedLength) << "data").raise();
}
string salt, key;
@ -97,9 +98,8 @@ int SrpClient::authenticate(IStatus* status, IClientBlock* cb)
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();
(Arg::Gds(isc_auth_datalength) << Arg::Num(charSize) <<
Arg::Num(RemotePassword::SRP_SALT_SIZE * 2) << "salt").raise();
}
salt.assign(saltAndKey, charSize);
dumpIt("Clnt: salt", salt);
@ -108,11 +108,10 @@ int SrpClient::authenticate(IStatus* status, IClientBlock* cb)
charSize = *saltAndKey++;
charSize += ((unsigned) *saltAndKey++) << 8;
if (charSize + 2 != length)
if (charSize != length - 2)
{
string msg;
msg.printf("Wrong length (%d) of key from server", charSize);
(Arg::Gds(isc_random) << msg).raise();
(Arg::Gds(isc_auth_datalength) << Arg::Num(charSize) <<
Arg::Num(length - 2) << "key").raise();
}
key.assign(saltAndKey, charSize);
dumpIt("Clnt: key(srvPub)", key);

View File

@ -183,7 +183,7 @@ public:
if (!(secDbName && secDbName[0]))
{
(Firebird::Arg::Gds(isc_random) << "Error getting security database name").raise();
Firebird::Arg::Gds(isc_secdb_name).raise();
}
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::dpbList, MAX_DPB_SIZE);

View File

@ -99,6 +99,7 @@ int SrpServer::authenticate(IStatus* status, IServerBlock* sb, IWriter* writerIn
unsigned int length;
const unsigned char* val = sb->getData(&length);
clientPubKey.assign(val, length);
dumpBin("Srv: clientPubKey", clientPubKey);
if (!clientPubKey.hasData())
{
@ -116,7 +117,7 @@ int SrpServer::authenticate(IStatus* status, IServerBlock* sb, IWriter* writerIn
secDbName = config->asString(secDbKey);
if (!(secDbName && secDbName[0]))
{
(Arg::Gds(isc_random) << "Error getting security database name").raise();
Arg::Gds(isc_secdb_name).raise();
}
ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
@ -221,14 +222,13 @@ int SrpServer::authenticate(IStatus* status, IServerBlock* sb, IWriter* writerIn
data += char(serverPubKey.length() >> 8);
data.append(serverPubKey);
dumpIt("Srv: serverPubKey", serverPubKey);
dumpIt("Srv: data", data);
dumpBin("Srv: data", data);
sb->putData(status, data.length(), data.c_str());
if (!status->isSuccess())
{
return AUTH_FAILED;
}
dumpIt("Srv: clientPubKey", clientPubKey);
server->serverSessionKey(sessionKey, clientPubKey.c_str(), verifier);
dumpIt("Srv: sessionKey", sessionKey);

View File

@ -213,6 +213,14 @@ void dumpIt(const char* name, const Firebird::string& str)
fprintf(stderr, "%s: '%s'\n", name, str.c_str());
}
void dumpBin(const char* name, const Firebird::string& str)
{
fprintf(stderr, "%s (%ld)\n", name, str.length());
for (size_t x=0; x<str.length(); ++x)
fprintf(stderr, "%02x ", str[x]);
fprintf(stderr, "\n");
}
void dumpIt(const char* name, const BigInteger& bi)
{
string x;

View File

@ -120,10 +120,12 @@ public:
void dumpIt(const char* name, const Firebird::BigInteger& bi);
void dumpIt(const char* name, const Firebird::UCharBuffer& data);
void dumpIt(const char* name, const Firebird::string& str);
void dumpBin(const char* name, const Firebird::string& str);
#else
void static inline dumpIt(const char* /*name*/, const Firebird::BigInteger& /*bi*/) { }
void static inline dumpIt(const char* /*name*/, const Firebird::UCharBuffer& /*data*/) { }
void static inline dumpIt(const char* /*name*/, const Firebird::string& /*str*/) { }
void static inline dumpBin(const char* /*name*/, const Firebird::string& /*str*/) { }
#endif

View File

@ -143,7 +143,7 @@ void FB_CARG SecurityDatabaseManagement::start(Firebird::IStatus* st, ILogonInfo
if (!(secDbName && secDbName[0]))
{
(Firebird::Arg::Gds(isc_random) << "Error getting security database name").raise();
Firebird::Arg::Gds(isc_secdb_name).raise();
}
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::dpbList, MAX_DPB_SIZE);

View File

@ -267,6 +267,10 @@ void SecurityDatabase::prepare()
// Attach as SYSDBA
dpb.insertString(isc_dpb_trusted_auth, SYSDBA_USER_NAME, strlen(SYSDBA_USER_NAME));
// Do not use other providers except current engine
const char* providers = "Providers=" CURRENT_ENGINE;
dpb.insertString(isc_dpb_config, providers, strlen(providers));
isc_db_handle tempHandle = 0;
isc_attach_database(status, 0, secureDbName, &tempHandle,
dpb.getBufferLength(), reinterpret_cast<const char*>(dpb.getBuffer()));
@ -307,7 +311,9 @@ int SecurityDatabase::verify(IWriter* authBlock, IServerBlock* sBlock)
return AUTH_CONTINUE;
}
string login(sBlock->getLogin());
const char* user = sBlock->getLogin();
string login(user ? user : "");
unsigned length;
const unsigned char* data = sBlock->getData(&length);
string passwordEnc;
@ -468,7 +474,7 @@ int SecurityDatabaseServer::authenticate(Firebird::IStatus* status, IServerBlock
const char* tmp = config->asString(secDbKey);
if (!tmp)
{
(Arg::Gds(isc_random) << "Error getting security database name").raise();
Arg::Gds(isc_secdb_name).raise();
}
secDbName = tmp;

View File

@ -106,7 +106,7 @@ static SLONG get_number(const SCHAR*);
static ULONG get_size(const SCHAR*, burp_fil*);
static gbak_action open_files(const TEXT *, const TEXT**, bool, USHORT,
const Firebird::ClumpletWriter&);
static int api_gbak(Firebird::UtilSvc*, const Switches& switches);
static int svc_api_gbak(Firebird::UtilSvc*, const Switches& switches);
static void burp_output(bool err, const SCHAR*, ...) ATTRIBUTE_FORMAT(2,3);
static void burp_usage(const Switches& switches);
static Switches::in_sw_tab_t* findSwitchOrThrow(Switches& switches, Firebird::string& sw);
@ -149,11 +149,11 @@ THREAD_ENTRY_DECLARE BURP_main(THREAD_ENTRY_PARAM arg)
}
static int api_gbak(Firebird::UtilSvc* uSvc, const Switches& switches)
static int svc_api_gbak(Firebird::UtilSvc* uSvc, const Switches& switches)
{
/**********************************************
*
* a p i _ g b a k
* s v c _ a p i _ g b a k
*
**********************************************
*
@ -172,12 +172,18 @@ static int api_gbak(Firebird::UtilSvc* uSvc, const Switches& switches)
Firebird::UtilSvc::ArgvType& argv = uSvc->argv;
const int argc = uSvc->argv.getCount();
Firebird::string files[2];
unsigned fileIndex = 0;
for (int itr = 1; itr < argc; ++itr)
{
const Switches::in_sw_tab_t* inSw = switches.findSwitch(argv[itr]);
if (! inSw)
{
if (argv[itr][0] && fileIndex < 2)
{
files[fileIndex++] = argv[itr];
}
continue;
}
@ -249,6 +255,8 @@ static int api_gbak(Firebird::UtilSvc* uSvc, const Switches& switches)
}
}
Firebird::string* dbName = flag_restore ? &files[1] : &files[0];
ISC_STATUS_ARRAY status;
FB_API_HANDLE svc_handle = 0;
@ -269,6 +277,10 @@ static int api_gbak(Firebird::UtilSvc* uSvc, const Switches& switches)
{
spb.insertString(isc_spb_password, pswd);
}
if (dbName->hasData())
{
spb.insertString(isc_spb_expected_db, *dbName);
}
#ifdef TRUSTED_AUTH
if (flag_trusted)
{
@ -450,7 +462,7 @@ int gbak(Firebird::UtilSvc* uSvc)
// test for "-service" switch
if (switches.exists(IN_SW_BURP_SE, argv.begin(), 1, argc))
return api_gbak(uSvc, switches);
return svc_api_gbak(uSvc, switches);
uSvc->started();

View File

@ -186,6 +186,7 @@ IntlParametersBlock::TagType IntlSpb::checkTag(UCHAR tag)
case isc_spb_trusted_auth:
case isc_spb_trusted_role:
case isc_spb_process_name:
case isc_spb_expected_db:
return TAG_STRING;
case isc_spb_command_line:

View File

@ -877,4 +877,31 @@ bool AuthReader::getInfo(string* name, string* method, PathName* secureDb)
return true;
}
#ifdef AUTH_BLOCK_DEBUG
void dumpAuthBlock(const char* text, ClumpletReader* pb, unsigned char param)
{
fprintf(stderr, "AuthBlock in %s:", text);
if (pb->find(param))
{
Firebird::AuthReader::AuthBlock tmp;
tmp.assign(pb->getBytes(), pb->getClumpLength());
Firebird::AuthReader rdr(tmp);
string name, method;
PathName secureDb;
bool x = false;
while (rdr.getInfo(&name, &method, &secureDb))
{
fprintf(stderr, " %s::%s::%s", name.c_str(), method.c_str(), secureDb.c_str());
x = true;
rdr.moveNext();
}
fprintf(stderr, "%s\n", x ? "" : " <empty>");
}
else
{
fprintf(stderr, " <missing>\n");
}
}
#endif
} // namespace

View File

@ -201,6 +201,13 @@ public:
bool getInfo(string* name, string* method, PathName* secDb);
};
//#define AUTH_BLOCK_DEBUG
#ifdef AUTH_BLOCK_DEBUG
void dumpAuthBlock(const char* text, ClumpletReader* pb, unsigned char param);
#else
static inline void dumpAuthBlock(const char*, ClumpletReader*, unsigned char) { }
#endif
} // namespace Firebird
#endif // CLUMPLETREADER_H

View File

@ -140,8 +140,15 @@ protected:
}
public:
typedef T* iterator;
typedef const T* const_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
typedef pointer iterator;
typedef const_pointer const_iterator;
Array<T, Storage>& operator =(const Array<T, Storage>& source)
{

View File

@ -228,6 +228,10 @@ namespace Firebird
{
return stringLength;
}
size_type getCount() const
{
return stringLength;
}
// Almost same as c_str(), but return 0, not "",
// when string has no data. Useful when interacting
// with old code, which does check for NULL.
@ -245,6 +249,10 @@ namespace Firebird
void reserve(size_type n = 0);
void resize(const size_type n, char_type c = ' ');
void grow(const size_type n)
{
resize(n);
}
pointer getBuffer(size_t l)
{

View File

@ -121,9 +121,6 @@ const char* AmNative = "native";
const char* AmTrusted = "trusted";
const char* AmMixed = "mixed";
const char* WIRE_CRYPT_DISABLED = "DISABLED";
const char* WIRE_CRYPT_ENABLED = "ENABLED";
const char* WIRE_CRYPT_REQUIRED = "REQUIRED";
const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{
@ -677,7 +674,7 @@ const char* Config::getPlugins(unsigned int type) const
return (const char*) values[KEY_PLUG_KEY_HOLDER];
}
(Firebird::Arg::Gds(isc_random) << "Internal error in Config::getPlugins()").raise();
(Firebird::Arg::Gds(isc_random) << "Internal error in Config::getPlugins(): unknown plugin type requested").raise();
return NULL; // compiler warning silencer
}
@ -717,8 +714,19 @@ const char* Config::getSecurityDatabase() const
return get<const char*>(KEY_SECURITY_DATABASE);
}
const char* Config::getWireCrypt(WireCryptMode wcMode) const
int Config::getWireCrypt(WireCryptMode wcMode) const
{
const char* rc = get<const char*>(KEY_WIRE_CRYPT);
return rc ? rc : wcMode == WC_CLIENT ? WIRE_CRYPT_ENABLED : WIRE_CRYPT_REQUIRED;
const char* wc = get<const char*>(KEY_WIRE_CRYPT);
if (!wc)
{
return wcMode == WC_CLIENT ? WIRE_CRYPT_ENABLED : WIRE_CRYPT_REQUIRED;
}
Firebird::NoCaseString wireCrypt(wc);
if (wireCrypt == "DISABLED")
return WIRE_CRYPT_DISABLED;
else if (wireCrypt == "ENABLED")
return WIRE_CRYPT_ENABLED;
else // the safest choice
return WIRE_CRYPT_REQUIRED;
}

View File

@ -75,9 +75,9 @@ extern const char* AmMixed;
enum AmCache {AM_UNKNOWN, AM_DISABLED, AM_ENABLED};
extern const char* WIRE_CRYPT_DISABLED;
extern const char* WIRE_CRYPT_ENABLED;
extern const char* WIRE_CRYPT_REQUIRED;
const int WIRE_CRYPT_DISABLED = 0;
const int WIRE_CRYPT_ENABLED = 1;
const int WIRE_CRYPT_REQUIRED = 2;
enum WireCryptMode {WC_CLIENT, WC_SERVER}; // Have different defaults
@ -335,7 +335,7 @@ public:
const char* getSecurityDatabase() const;
const char* getWireCrypt(WireCryptMode wcMode) const;
int getWireCrypt(WireCryptMode wcMode) const;
};
// Implementation of interface to access master configuration file

View File

@ -282,6 +282,7 @@
#define isc_spb_host_name 121
#define isc_spb_os_user 122
#define isc_spb_config 123
#define isc_spb_expected_db 124
#define isc_spb_connect_timeout isc_dpb_connect_timeout
#define isc_spb_dummy_packet_interval isc_dpb_dummy_packet_interval

View File

@ -761,6 +761,17 @@ static const struct {
{"include_miss", 335545057},
{"protect_ownership", 335545058},
{"badvarnum", 335545059},
{"sec_context", 335545060},
{"multi_segment", 335545061},
{"login_changed", 335545062},
{"auth_handshake_limit", 335545063},
{"wirecrypt_incompatible", 335545064},
{"miss_wirecrypt", 335545065},
{"wirecrypt_key", 335545066},
{"wirecrypt_plugin", 335545067},
{"secdb_name", 335545068},
{"auth_data", 335545069},
{"auth_datalength", 335545070},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -795,6 +795,17 @@ const ISC_STATUS isc_include_depth = 335545056L;
const ISC_STATUS isc_include_miss = 335545057L;
const ISC_STATUS isc_protect_ownership = 335545058L;
const ISC_STATUS isc_badvarnum = 335545059L;
const ISC_STATUS isc_sec_context = 335545060L;
const ISC_STATUS isc_multi_segment = 335545061L;
const ISC_STATUS isc_login_changed = 335545062L;
const ISC_STATUS isc_auth_handshake_limit = 335545063L;
const ISC_STATUS isc_wirecrypt_incompatible = 335545064L;
const ISC_STATUS isc_miss_wirecrypt = 335545065L;
const ISC_STATUS isc_wirecrypt_key = 335545066L;
const ISC_STATUS isc_wirecrypt_plugin = 335545067L;
const ISC_STATUS isc_secdb_name = 335545068L;
const ISC_STATUS isc_auth_data = 335545069L;
const ISC_STATUS isc_auth_datalength = 335545070L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1239,7 +1250,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 = 1183;
const ISC_STATUS isc_err_max = 1194;
#else /* c definitions */
@ -2004,6 +2015,17 @@ const ISC_STATUS isc_err_max = 1183;
#define isc_include_miss 335545057L
#define isc_protect_ownership 335545058L
#define isc_badvarnum 335545059L
#define isc_sec_context 335545060L
#define isc_multi_segment 335545061L
#define isc_login_changed 335545062L
#define isc_auth_handshake_limit 335545063L
#define isc_wirecrypt_incompatible 335545064L
#define isc_miss_wirecrypt 335545065L
#define isc_wirecrypt_key 335545066L
#define isc_wirecrypt_plugin 335545067L
#define isc_secdb_name 335545068L
#define isc_auth_data 335545069L
#define isc_auth_datalength 335545070L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2448,7 +2470,7 @@ const ISC_STATUS isc_err_max = 1183;
#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 1183
#define isc_err_max 1194
#endif

View File

@ -764,6 +764,17 @@ Data source : @4"}, /* eds_statement */
{335545057, "File to include not found"}, /* include_miss */
{335545058, "Only the owner can change the ownership"}, /* protect_ownership */
{335545059, "undefined variable number"}, /* badvarnum */
{335545060, "Missing security context for database @1"}, /* sec_context */
{335545061, "Missing segment @1 in multisegment connect block parameter"}, /* multi_segment */
{335545062, "Different logins in connect and attach packets - client library error"}, /* login_changed */
{335545063, "Exceeded exchange limit during authentication handshake"}, /* auth_handshake_limit */
{335545064, "Incompatible wire encryption levels requested on client and server"}, /* wirecrypt_incompatible */
{335545065, "Client attempted to attach unencrypted but wire encryption is required"}, /* miss_wirecrypt */
{335545066, "Client attempted to start wire encryption using unknown key @1"}, /* wirecrypt_key */
{335545067, "Client attempted to start wire encryption using unsupported plugin @1"}, /* wirecrypt_plugin */
{335545068, "Error getting security database name from configuration file"}, /* secdb_name */
{335545069, "Client authentication plugin is missing required data from server"}, /* auth_data */
{335545070, "Client authentication plugin expected @2 bytes of @3 from server, got @1"}, /* auth_datalength */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */

View File

@ -760,6 +760,17 @@ static const struct {
{335545057, -902}, /* 737 include_miss */
{335545058, -552}, /* 738 protect_ownership */
{335545059, -901}, /* 739 badvarnum */
{335545060, -902}, /* 740 sec_context */
{335545061, -902}, /* 741 multi_segment */
{335545062, -902}, /* 742 login_changed */
{335545063, -902}, /* 743 auth_handshake_limit */
{335545064, -902}, /* 744 wirecrypt_incompatible */
{335545065, -902}, /* 745 miss_wirecrypt */
{335545066, -902}, /* 746 wirecrypt_key */
{335545067, -902}, /* 747 wirecrypt_plugin */
{335545068, -902}, /* 748 secdb_name */
{335545069, -902}, /* 749 auth_data */
{335545070, -902}, /* 750 auth_datalength */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -760,6 +760,17 @@ static const struct {
{335545057, "XX000"}, // 737 include_miss
{335545058, "28000"}, // 738 protect_ownership
{335545059, "HY000"}, // 739 badvarnum
{335545060, "28000"}, // 740 sec_context
{335545061, "28000"}, // 741 multi_segment
{335545062, "28000"}, // 742 login_changed
{335545063, "28000"}, // 743 auth_handshake_limit
{335545064, "28000"}, // 744 wirecrypt_incompatible
{335545065, "28000"}, // 745 miss_wirecrypt
{335545066, "28000"}, // 746 wirecrypt_key
{335545067, "28000"}, // 747 wirecrypt_plugin
{335545068, "28000"}, // 748 secdb_name
{335545069, "28000"}, // 749 auth_data
{335545070, "28000"}, // 750 auth_datalength
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -946,7 +946,7 @@ static void rollback(thread_db*, jrd_tra*, const bool);
static bool shutdown_database(Database*, const bool);
static void strip_quotes(string&);
static void purge_attachment(thread_db*, JAttachment*, const bool);
static void getUserInfo(UserId&, const DatabaseOptions&, const RefPtr<Config>*);
static void getUserInfo(UserId&, const DatabaseOptions&, const char*, const RefPtr<Config>*);
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM);
@ -955,7 +955,7 @@ TraceFailedConnection::TraceFailedConnection(const char* filename, const Databas
m_filename(filename),
m_options(options)
{
getUserInfo(m_id, *m_options, NULL);
getUserInfo(m_id, *m_options, m_filename, NULL);
}
@ -1276,7 +1276,7 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
}
// Check for correct credentials supplied
getUserInfo(userId, options, &config);
getUserInfo(userId, options, org_filename.c_str(), &config);
}
catch (const Exception& ex)
{
@ -2363,7 +2363,7 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
}
// Check for correct credentials supplied
getUserInfo(userId, options, &config);
getUserInfo(userId, options, org_filename.c_str(), &config);
}
catch (const Exception& ex)
{
@ -5462,6 +5462,7 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
}
ClumpletReader rdr(ClumpletReader::dpbList, dpb, dpb_length, dpbErrorRaise);
dumpAuthBlock("DatabaseOptions::get()", &rdr, isc_dpb_auth_block);
dpb_utf8_filename = rdr.find(isc_dpb_utf8_filename);
@ -6941,7 +6942,8 @@ static VdnResult verifyDatabaseName(const PathName& name, ISC_STATUS* status, bo
@param
**/
static void getUserInfo(UserId& user, const DatabaseOptions& options, const RefPtr<Config>* config)
static void getUserInfo(UserId& user, const DatabaseOptions& options,
const char* dbName, const RefPtr<Config>* config)
{
bool wheel = false;
int id = -1, group = -1; // CVC: This var contained trash
@ -6974,7 +6976,7 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options, const RefP
{
if (config && (secureDb != (*config)->getSecurityDatabase()))
{
(Arg::Gds(isc_login) << Arg::Gds(isc_random) << "No SecDb match").raise();
(Arg::Gds(isc_sec_context) << dbName).raise();
}
}
else

View File

@ -756,6 +756,7 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
// Process the service parameter block.
ClumpletReader spb(ClumpletReader::spbList, spb_data, spb_length, spbVersionError);
dumpAuthBlock("Jrd::Service() ctor", &spb, isc_spb_auth_block);
getOptions(spb);
// Perhaps checkout the user in the security database.

View File

@ -1,7 +1,7 @@
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
--
('2013-09-04 11:02:00', 'JRD', 0, 740)
('2013-10-15 17:48:59', 'JRD', 0, 751)
('2012-01-23 20:10:30', 'QLI', 1, 532)
('2009-07-16 05:26:11', 'GFIX', 3, 121)
('1996-11-07 13:39:40', 'GPRE', 4, 1)

View File

@ -847,6 +847,17 @@ Data source : @4', NULL, NULL)
('include_miss', NULL, 'config_file.cpp', NULL, 0, 737, NULL, 'File to include not found', NULL, NULL);
('protect_ownership', 'check_owner', 'vio.cpp', NULL, 0, 738, NULL, 'Only the owner can change the ownership', NULL, NULL);
('badvarnum', NULL, NULL, NULL, 0, 739, NULL, 'undefined variable number', NULL, NULL);
('sec_context', 'getUserInfo', 'jrd.cpp', NULL, 0, 740, NULL, 'Missing security context for database @1', NULL, NULL);
('multi_segment', 'getMultiPartConnectParameter', 'server.cpp', NULL, 0, 741, NULL, 'Missing segment @1 in multisegment connect block parameter', NULL, NULL);
('login_changed', 'ServerAuth::ServerAuth', 'server.cpp', NULL, 0, 742, NULL, 'Different logins in connect and attach packets - client library error', NULL, NULL);
('auth_handshake_limit', 'ServerAuth::authenticate', 'server.cpp', NULL, 0, 743, NULL, 'Exceeded exchange limit during authentication handshake', NULL, NULL);
('wirecrypt_incompatible', 'requiredEncryption', 'server.cpp', NULL, 0, 744, NULL, 'Incompatible wire encryption levels requested on client and server', NULL, NULL);
('miss_wirecrypt', NULL, 'server.cpp', NULL, 0, 745, NULL, 'Client attempted to attach unencrypted but wire encryption is required', NULL, NULL);
('wirecrypt_key', 'start_crypt', 'server.cpp', NULL, 0, 746, NULL, 'Client attempted to start wire encryption using unknown key @1', NULL, NULL);
('wirecrypt_plugin', 'start_crypt', 'server.cpp', NULL, 0, 747, NULL, 'Client attempted to start wire encryption using unsupported plugin @1', NULL, NULL);
('secdb_name', NULL, NULL, NULL, 0, 748, NULL, 'Error getting security database name from configuration file', NULL, NULL);
('auth_data', NULL, NULL, NULL, 0, 749, NULL, 'Client authentication plugin is missing required data from server', NULL, NULL);
('auth_datalength', NULL, NULL, NULL, 0, 750, NULL, 'Client authentication plugin expected @2 bytes of @3 from server, got @1', NULL, NULL);
-- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);

View File

@ -746,6 +746,17 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-902, 'XX', '000', 0, 737, 'include_miss', NULL, NULL)
(-552, '28', '000', 0, 738, 'protect_ownership', NULL, NULL)
(-901, 'HY', '000', 0, 739, 'badvarnum', NULL, NULL)
(-902, '28', '000', 0, 740, 'sec_context', NULL, NULL);
(-902, '28', '000', 0, 741, 'multi_segment', NULL, NULL);
(-902, '28', '000', 0, 742, 'login_changed', NULL, NULL);
(-902, '28', '000', 0, 743, 'auth_handshake_limit', NULL, NULL);
(-902, '28', '000', 0, 744, 'wirecrypt_incompatible', NULL, NULL);
(-902, '28', '000', 0, 745, 'miss_wirecrypt', NULL, NULL);
(-902, '28', '000', 0, 746, 'wirecrypt_key', NULL, NULL);
(-902, '28', '000', 0, 747, 'wirecrypt_plugin', NULL, NULL);
(-902, '28', '000', 0, 748, 'secdb_name', NULL, NULL);
(-902, '28', '000', 0, 749, 'auth_data', NULL, NULL);
(-902, '28', '000', 0, 750, 'auth_datalength', NULL, NULL);
-- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)

View File

@ -661,8 +661,8 @@ namespace Remote {
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(ClntAuthBlock&, PathName&, bool, ClumpletWriter&, PathName&, bool);
static rem_port* analyze_service(ClntAuthBlock&, PathName&, bool, ClumpletReader&, bool);
static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned flags,
ClumpletWriter& pb, const ParametersSet& parSet, PathName& node_name, PathName* ref_db_name);
static void batch_gds_receive(rem_port*, struct rmtque *, USHORT);
static void batch_dsql_fetch(rem_port*, struct rmtque *, USHORT);
static void clear_queue(rem_port*);
@ -674,7 +674,7 @@ static THREAD_ENTRY_DECLARE event_thread(THREAD_ENTRY_PARAM);
static Rvnt* find_event(rem_port*, SLONG);
static bool get_new_dpb(ClumpletWriter&, const ParametersSet&);
static void info(IStatus*, Rdb*, P_OP, USHORT, USHORT, USHORT,
const UCHAR*, USHORT, const UCHAR*, ULONG, UCHAR*, ClntAuthBlock* cBlock = NULL);
const UCHAR*, USHORT, const UCHAR*, ULONG, UCHAR*);
static void init(IStatus*, ClntAuthBlock&, rem_port*, P_OP, PathName&,
ClumpletWriter&, IntlParametersBlock&, ICryptKeyCallback* cryptCallback);
static Rtr* make_transaction(Rdb*, USHORT);
@ -702,14 +702,17 @@ 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(ClntAuthBlock& authItr, ClumpletWriter& dpb,
const ParametersSet* tags, rem_port* port);
static void authReceiveResponse(ClntAuthBlock& authItr, rem_port* port, Rdb* rdb,
IStatus* status, PACKET* packet, bool checkKeys);
static void authReceiveResponse(bool havePacket, ClntAuthBlock& authItr, rem_port* port,
Rdb* rdb, IStatus* status, PACKET* packet, bool checkKeys);
static AtomicCounter remote_event_id;
static const unsigned ANALYZE_UV = 0x01;
static const unsigned ANALYZE_LOOPBACK = 0x02;
static const unsigned ANALYZE_MOUNTS = 0x03;
inline static void reset(IStatus* status) throw()
{
status->init();
@ -753,13 +756,17 @@ IAttachment* Provider::attach(IStatus* status, const char* filename, unsigned in
reset(status);
ClumpletWriter newDpb(ClumpletReader::dpbList, MAX_DPB_SIZE, dpb, dpb_length);
const bool user_verification = get_new_dpb(newDpb, dpbParam);
unsigned flags = ANALYZE_MOUNTS;
if (get_new_dpb(newDpb, dpbParam))
flags |= ANALYZE_UV;
if (loopback)
flags |= ANALYZE_LOOPBACK;
PathName expanded_name(filename);
PathName node_name;
ClntAuthBlock cBlock(&expanded_name, &newDpb, &dpbParam);
rem_port* port = analyze(cBlock, expanded_name, user_verification, newDpb, node_name, loopback);
rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL);
if (!port)
{
@ -770,13 +777,13 @@ IAttachment* Provider::attach(IStatus* status, const char* filename, unsigned in
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
// The client may have set a parameter for dummy_packet_interval. Add that to the
// the DPB so the server can pay attention to it. Note: allocation code must
// ensure sufficient space has been added.
// the DPB so the server can pay attention to it.
add_other_params(port, newDpb, dpbParam);
add_working_directory(newDpb, node_name);
IntlDpb intl;
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: call init for DB='%s'\n", expanded_name.c_str()));
init(status, cBlock, port, op_attach, expanded_name, newDpb, intl, cryptCallback);
Attachment* a = new Attachment(port->port_context, filename);
@ -1336,13 +1343,17 @@ Firebird::IAttachment* Provider::create(IStatus* status, const char* filename,
ClumpletWriter newDpb(ClumpletReader::dpbList, MAX_DPB_SIZE,
reinterpret_cast<const UCHAR*>(dpb), dpb_length);
const bool user_verification = get_new_dpb(newDpb, dpbParam);
unsigned flags = ANALYZE_MOUNTS;
if (get_new_dpb(newDpb, dpbParam))
flags |= ANALYZE_UV;
if (loopback)
flags |= ANALYZE_LOOPBACK;
PathName expanded_name(filename);
PathName node_name;
ClntAuthBlock cBlock(&expanded_name, &newDpb, &dpbParam);
rem_port* port = analyze(cBlock, expanded_name, user_verification, newDpb, node_name, loopback);
rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL);
if (!port)
{
@ -4560,14 +4571,25 @@ Firebird::IService* Provider::attachSvc(IStatus* status, const char* service,
{
reset(status);
PathName expanded_name(service);
PathName node_name, expanded_name(service);
ClumpletWriter newSpb(ClumpletReader::spbList, MAX_DPB_SIZE, spb, spbLength);
const bool user_verification = get_new_dpb(newSpb, spbParam);
ClntAuthBlock cBlock(NULL, &newSpb, &spbParam);
cBlock.loadClnt(newSpb, &spbParam);
rem_port* port = analyze_service(cBlock, expanded_name, user_verification, newSpb, loopback);
unsigned flags = 0;
if (get_new_dpb(newSpb, spbParam))
flags |= ANALYZE_UV;
if (loopback)
flags |= ANALYZE_LOOPBACK;
PathName refDbName;
if (newSpb.find(isc_spb_expected_db))
{
newSpb.getPath(refDbName);
}
rem_port* port = analyze(cBlock, expanded_name, flags, newSpb, spbParam, node_name, &refDbName);
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
Rdb* rdb = port->port_context;
@ -4581,8 +4603,6 @@ Firebird::IService* Provider::attachSvc(IStatus* status, const char* service,
IntlSpb intl;
init(status, cBlock, port, op_service_attach, expanded_name, newSpb, intl, cryptCallback);
cBlock.saveServiceDataTo(port);
Firebird::IService* s = new Service(rdb);
s->addRef();
return s;
@ -4718,12 +4738,9 @@ void Service::query(IStatus* status,
rem_port* port = rdb->rdb_port;
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
ClntAuthBlock cBlock(NULL, NULL, NULL);
cBlock.loadServiceDataFrom(port);
info(status, rdb, op_service_info, rdb->rdb_id, 0,
sendLength, sendItems, receiveLength, receiveItems,
bufferLength, buffer, &cBlock);
bufferLength, buffer);
}
catch (const Exception& ex)
{
@ -5322,12 +5339,33 @@ static void authenticateStep0(ClntAuthBlock& cBlock)
}
static rem_port* analyze(ClntAuthBlock& cBlock,
PathName& file_name,
bool uv_flag,
ClumpletWriter& dpb,
PathName& node_name,
bool loopback)
static void secureAuthentication(ClntAuthBlock& cBlock, rem_port* port)
{
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: secureAuthentication\n"));
if (!port)
return;
Rdb* rdb = port->port_context;
fb_assert(rdb);
PACKET* packet = &rdb->rdb_packet;
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: secureAuthentication: port OK, op=%d\n", packet->p_operation));
if (packet->p_operation == op_cond_accept)
{
LocalStatus st;
authReceiveResponse(true, cBlock, port, rdb, &st, packet, true);
if (!st.isSuccess())
{
status_exception::raise(st.get());
}
}
}
static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned flags,
ClumpletWriter& pb, const ParametersSet& parSet, PathName& node_name, PathName* ref_db_name)
{
/**************************************
*
@ -5336,9 +5374,9 @@ static rem_port* analyze(ClntAuthBlock& cBlock,
**************************************
*
* Functional description
* Analyze a file specification and determine whether
* Analyze an attach specification and determine whether
* a remote server is required, and if so, what protocol
* to use. If the database can be accessed via the
* to use. If the target can be accessed via the
* remote subsystem, return address of a port block
* with which to communicate with the server.
* Otherwise, return NULL.
@ -5347,53 +5385,61 @@ static rem_port* analyze(ClntAuthBlock& cBlock,
*
**************************************/
// Analyze the file name to see if a remote connection is required. If not,
// quietly (sic) return.
cBlock.loadClnt(dpb, &dpbParam);
authenticateStep0(cBlock);
rem_port* port = NULL;
#ifdef WIN_NT
if (ISC_analyze_protocol(PROTOCOL_XNET, file_name, node_name))
try
{
port = XNET_analyze(&cBlock, file_name, uv_flag, cBlock.getConfig());
cBlock.loadClnt(pb, &parSet);
authenticateStep0(cBlock);
#ifdef WIN_NT
if (ISC_analyze_protocol(PROTOCOL_XNET, attach_name, node_name))
{
port = XNET_analyze(&cBlock, attach_name, flags & ANALYZE_UV, cBlock.getConfig(), ref_db_name);
}
else if (ISC_analyze_protocol(PROTOCOL_WNET, file_name, node_name) ||
ISC_analyze_pclan(file_name, node_name))
else if (ISC_analyze_protocol(PROTOCOL_WNET, attach_name, node_name) ||
ISC_analyze_pclan(attach_name, node_name))
{
if (node_name.isEmpty())
{
node_name = WNET_LOCALHOST;
}
else
{
ISC_unescape(node_name);
ISC_utf8ToSystem(node_name);
}
port = WNET_analyze(&cBlock, file_name, node_name.c_str(), uv_flag, cBlock.getConfig());
port = WNET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_UV,
cBlock.getConfig(), ref_db_name);
}
else
#endif
if (ISC_analyze_protocol(PROTOCOL_INET, file_name, node_name) ||
ISC_analyze_tcp(file_name, node_name))
if (ISC_analyze_protocol(PROTOCOL_INET, attach_name, node_name) ||
ISC_analyze_tcp(attach_name, node_name))
{
if (node_name.isEmpty())
{
node_name = INET_LOCALHOST;
}
else
{
ISC_unescape(node_name);
ISC_utf8ToSystem(node_name);
}
port = INET_analyze(&cBlock, file_name, node_name.c_str(), uv_flag, dpb, cBlock.getConfig());
port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_UV, pb,
cBlock.getConfig(), ref_db_name);
}
// We have a local connection string. If it's a file on a network share,
// try to connect to the corresponding host remotely.
if (flags & ANALYZE_MOUNTS)
{
#ifdef WIN_NT
PathName expanded_name = file_name;
if (!port)
{
PathName expanded_name = attach_name;
ISC_expand_share(expanded_name);
if (ISC_analyze_pclan(expanded_name, node_name))
@ -5401,142 +5447,78 @@ static rem_port* analyze(ClntAuthBlock& cBlock,
ISC_unescape(node_name);
ISC_utf8ToSystem(node_name);
port = WNET_analyze(&cBlock, expanded_name, node_name.c_str(), uv_flag, cBlock.getConfig());
port = WNET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_UV,
cBlock.getConfig(), ref_db_name);
}
}
#endif
#ifndef NO_NFS
if (!port)
{
PathName expanded_name = file_name;
PathName expanded_name = attach_name;
if (ISC_analyze_nfs(expanded_name, node_name))
{
ISC_unescape(node_name);
ISC_utf8ToSystem(node_name);
port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), uv_flag, dpb, cBlock.getConfig());
port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_UV, pb,
cBlock.getConfig(), ref_db_name);
}
}
#endif
}
if (loopback)
if ((flags & ANALYZE_LOOPBACK) && !port)
{
// We still have a local connection string but failed to connect so far.
// If we're a pure client, attempt connect to the localhost.
// We have a local connection string.
// If we are in loopback mode attempt connect to a localhost.
if (node_name.isEmpty())
{
#ifdef WIN_NT
if (!port)
{
port = XNET_analyze(&cBlock, file_name, uv_flag, cBlock.getConfig());
port = XNET_analyze(&cBlock, attach_name, flags & ANALYZE_UV, cBlock.getConfig(), ref_db_name);
}
if (!port)
{
port = WNET_analyze(&cBlock, file_name, WNET_LOCALHOST, uv_flag, cBlock.getConfig());
port = WNET_analyze(&cBlock, attach_name, WNET_LOCALHOST, flags & ANALYZE_UV,
cBlock.getConfig(), ref_db_name);
}
#endif
if (!port)
{
port = INET_analyze(&cBlock, file_name, INET_LOCALHOST, uv_flag, dpb, cBlock.getConfig());
port = INET_analyze(&cBlock, attach_name, INET_LOCALHOST, flags & ANALYZE_UV, pb,
cBlock.getConfig(), ref_db_name);
}
}
}
return port;
}
static rem_port* analyze_service(ClntAuthBlock& cBlock,
PathName& service_name,
bool uv_flag,
ClumpletReader& spb,
bool loopback)
{
/**************************************
*
* a n a l y z e _ s e r v i c e
*
**************************************
*
* Functional description
* Analyze a service specification and determine whether
* a remote server is required, and if so, what protocol
* to use. If the database can be accessed via the
* remote subsystem, return address of a port block
* with which to communicate with the server.
* Otherwise, return NULL.
*
**************************************/
// 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(NULL, service_name, uv_flag, cBlock.getConfig());
}
if (ISC_analyze_protocol(PROTOCOL_WNET, service_name, node_name) ||
ISC_analyze_pclan(service_name, node_name))
{
if (node_name.isEmpty())
{
node_name = WNET_LOCALHOST;
}
return WNET_analyze(NULL, service_name, node_name.c_str(), uv_flag, cBlock.getConfig());
}
#endif
if (ISC_analyze_protocol(PROTOCOL_INET, service_name, node_name) ||
ISC_analyze_tcp(service_name, node_name))
{
if (node_name.isEmpty())
{
node_name = INET_LOCALHOST;
}
return INET_analyze(NULL, service_name, node_name.c_str(), uv_flag, spb, cBlock.getConfig());
}
rem_port* port = NULL;
if (loopback)
{
// We have a local connection string. If we're a pure client,
// attempt connect to a localhost.
if (node_name.isEmpty())
{
#if defined(WIN_NT)
if (!port)
{
port = XNET_analyze(NULL, service_name, uv_flag, cBlock.getConfig());
}
if (!port)
{
port = WNET_analyze(NULL, service_name, WNET_LOCALHOST, uv_flag, cBlock.getConfig());
}
#endif
if (!port)
{
port = INET_analyze(NULL, service_name, INET_LOCALHOST, uv_flag, spb, cBlock.getConfig());
}
}
}
if (!port)
{
Arg::Gds(isc_unavailable).raise();
}
secureAuthentication(cBlock, port);
}
catch (const status_exception& ex)
{
const ISC_STATUS* s = ex.value();
if (s[1] != isc_unavailable)
{
(Arg::Gds(isc_unavailable) << Arg::StatusVector(s)).raise();
}
else
{
throw;
}
}
return port;
}
static void clear_stmt_que(rem_port* port, Rsr* statement)
{
/**************************************
@ -6095,8 +6077,7 @@ static void info(IStatus* status,
USHORT recv_item_length,
const UCHAR* recv_items,
ULONG buffer_length,
UCHAR* buffer,
ClntAuthBlock* cBlock)
UCHAR* buffer)
{
/**************************************
*
@ -6136,19 +6117,8 @@ static void info(IStatus* status,
try
{
if (operation == op_service_info)
{
// Probably communicate with services auth
fb_assert(cBlock);
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: info() calls authReceiveResponse\n"));
authReceiveResponse(*cBlock, rdb->rdb_port, rdb, status, packet, false);
}
else
{
// Just get response from server
receive_response(status, rdb, packet);
}
}
catch (const Exception&)
{
response->p_resp_data = temp;
@ -6162,6 +6132,11 @@ static void info(IStatus* status,
static void authFillParametersBlock(ClntAuthBlock& cBlock, ClumpletWriter& dpb,
const ParametersSet* tags, rem_port* port)
{
if (cBlock.authComplete)
{
return; // Already authenticated
}
LocalStatus s;
cBlock.resetDataFromPlugin();
@ -6231,15 +6206,23 @@ static void REMOTE_free_string(CSTRING* tmp)
}
}
static void authReceiveResponse(ClntAuthBlock& cBlock, rem_port* port, Rdb* rdb,
IStatus* status, PACKET* packet, bool checkKeys)
static void authReceiveResponse(bool havePacket, ClntAuthBlock& cBlock, rem_port* port,
Rdb* rdb, IStatus* status, PACKET* packet, bool checkKeys)
{
LocalStatus s;
for (;;)
{
// Get response
if (!havePacket)
{
receive_packet(port, packet);
}
else
{
fb_assert(packet->p_operation == op_cond_accept);
}
havePacket = false; // havePacket means first packet is already received
// Check response
cstring* n = NULL;
@ -6256,7 +6239,16 @@ static void authReceiveResponse(ClntAuthBlock& cBlock, rem_port* port, Rdb* rdb,
d = &packet->p_auth_cont.p_data;
n = &packet->p_auth_cont.p_name;
port->addServerKeys(&packet->p_auth_cont.p_keys);
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: authReceiveResponse: ont_auth d=%d n=%d '%.*s' 0x%x\n",
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: authReceiveResponse: cont_auth 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;
case op_cond_accept:
d = &packet->p_acpd.p_acpt_data;
n = &packet->p_acpd.p_acpt_plugin;
port->addServerKeys(&packet->p_acpd.p_acpt_keys);
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: authReceiveResponse: cond_accept 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;
@ -6285,6 +6277,7 @@ static void authReceiveResponse(ClntAuthBlock& cBlock, rem_port* port, Rdb* rdb,
REMOTE_check_response(status, rdb, packet, checkKeys);
// successfully attached
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: authReceiveResponse: OK!\n"));
cBlock.authComplete = true;
rdb->rdb_id = packet->p_resp.p_resp_object;
// try to start crypt
@ -6392,7 +6385,7 @@ static void init(IStatus* status, ClntAuthBlock& cBlock, rem_port* port, P_OP op
send_packet(port, packet);
authReceiveResponse(cBlock, port, rdb, status, packet, true);
authReceiveResponse(false, cBlock, port, rdb, status, packet, true);
}
catch (const Exception&)
{
@ -6681,6 +6674,9 @@ static void receive_packet_noqueue(rem_port* port, PACKET* packet)
// Receive responses for all deferred packets that were already sent
Rdb* rdb = port->port_context;
if (port->port_deferred_packets)
{
while (port->port_deferred_packets->getCount())
{
rem_que_packet* const p = port->port_deferred_packets->begin();
@ -6743,6 +6739,7 @@ static void receive_packet_noqueue(rem_port* port, PACKET* packet)
REMOTE_free_packet(port, &p->packet, true);
port->port_deferred_packets->remove(p);
}
}
receive_packet_with_callback(port, packet);
}
@ -7197,6 +7194,8 @@ static void send_packet(rem_port* port, PACKET* packet)
// Send packets that were deferred
if (port->port_deferred_packets)
{
for (rem_que_packet* p = port->port_deferred_packets->begin();
p < port->port_deferred_packets->end(); p++)
{
@ -7209,6 +7208,7 @@ static void send_packet(rem_port* port, PACKET* packet)
p->sent = true;
}
}
}
if (!port->send(packet))
{
@ -7310,21 +7310,12 @@ static void svcstart(IStatus* status,
*
**************************************/
// Get ready for multi-hop auth
ClntAuthBlock cBlock(NULL, NULL, NULL);
cBlock.loadServiceDataFrom(rdb->rdb_port);
ClumpletWriter send(ClumpletReader::SpbStart, MAX_DPB_SIZE, items, item_length);
if (rdb->rdb_port->port_protocol < PROTOCOL_VERSION13)
{
// This is FB < 3.0. Lets convert the UTF8 strings to the OS codepage.
IntlSpbStart().fromUtf8(send, 0);
}
else
{
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: svcstart calls authFillParametersBlock\n"));
authFillParametersBlock(cBlock, send, &spbStartParam, rdb->rdb_port);
}
// Build the primary packet to get the operation started.
PACKET* packet = &rdb->rdb_packet;
@ -7344,7 +7335,7 @@ static void svcstart(IStatus* status,
try
{
authReceiveResponse(cBlock, rdb->rdb_port, rdb, status, packet, true);
receive_response(status, rdb, packet);
}
catch (const Exception&)
{
@ -7473,8 +7464,8 @@ ClntAuthBlock::ClntAuthBlock(const Firebird::PathName* fileName, Firebird::Clump
: pluginList(getPool()), serverPluginList(getPool()),
userName(getPool()), password(getPool()),
dataForPlugin(getPool()), dataFromPlugin(getPool()),
cryptKeys(getPool()), dpbConfig(getPool()), hasCryptKey(false),
plugins(PluginType::AuthClient, FB_AUTH_CLIENT_VERSION, upInfo),
cryptKeys(getPool()), dpbConfig(getPool()),
hasCryptKey(false), plugins(PluginType::AuthClient, FB_AUTH_CLIENT_VERSION, upInfo),
authComplete(false), firstTime(true)
{
if (dpb && tags && dpb->find(tags->config_text))
@ -7664,18 +7655,6 @@ bool ClntAuthBlock::checkPluginName(Firebird::PathName& nameToCheck)
return false;
}
void ClntAuthBlock::saveServiceDataTo(rem_port* port)
{
port->port_login = userName;
port->port_password = password;
}
void ClntAuthBlock::loadServiceDataFrom(rem_port* port)
{
userName = port->port_login;
password = port->port_password;
}
void ClntAuthBlock::putKey(IStatus* status, FbCryptKey* cryptKey)
{
status->init();

View File

@ -448,7 +448,8 @@ static rem_port* inet_try_connect( PACKET*,
const PathName&,
const TEXT*,
ClumpletReader&,
RefPtr<Config>*);
RefPtr<Config>*,
const PathName*);
static bool_t inet_write(XDR*); //, int);
#ifdef DEBUG
@ -523,7 +524,8 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock,
const TEXT* node_name,
bool uv_flag,
ClumpletReader &dpb,
RefPtr<Config>* config)
RefPtr<Config>* config,
const PathName* ref_db_name)
{
/**************************************
*
@ -608,12 +610,13 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock,
// Try connection using first set of protocols
rem_port* port = inet_try_connect(packet, rdb, file_name, node_name, dpb, config);
rem_port* port = inet_try_connect(packet, rdb, file_name, node_name, dpb, config, ref_db_name);
P_ACPT* accept = NULL;
switch (packet->p_operation)
{
case op_accept_data:
case op_cond_accept:
accept = &packet->p_acpd;
if (cBlock)
{
@ -2680,7 +2683,8 @@ static rem_port* inet_try_connect(PACKET* packet,
const PathName& file_name,
const TEXT* node_name,
ClumpletReader& dpb,
RefPtr<Config>* config)
RefPtr<Config>* config,
const PathName* ref_db_name)
{
/**************************************
*
@ -2701,8 +2705,10 @@ static rem_port* inet_try_connect(PACKET* packet,
cnct->p_cnct_operation = op_attach;
cnct->p_cnct_cversion = CONNECT_VERSION3;
cnct->p_cnct_client = ARCHITECTURE;
cnct->p_cnct_file.cstr_length = (ULONG) file_name.length();
cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(file_name.c_str());
const PathName& cnct_file(ref_db_name ? (*ref_db_name) : file_name);
cnct->p_cnct_file.cstr_length = (ULONG) cnct_file.length();
cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(cnct_file.c_str());
// If we can't talk to a server, punt. Let somebody else generate
// an error. status_vector will have the network error info.

View File

@ -34,7 +34,7 @@ namespace Firebird
}
rem_port* INET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*,
bool, Firebird::ClumpletReader&, Firebird::RefPtr<Config>*);
bool, Firebird::ClumpletReader&, Firebird::RefPtr<Config>*, const Firebird::PathName*);
rem_port* INET_connect(const TEXT*, struct packet*, USHORT, Firebird::ClumpletReader*,
Firebird::RefPtr<Config>*);
rem_port* INET_reconnect(SOCKET);

View File

@ -105,7 +105,8 @@ rem_port* WNET_analyze(ClntAuthBlock* cBlock,
const PathName& file_name,
const TEXT* node_name,
bool uv_flag,
RefPtr<Config>* config)
RefPtr<Config>* config,
const Firebird::PathName* ref_db_name)
{
/**************************************
*
@ -157,8 +158,10 @@ rem_port* WNET_analyze(ClntAuthBlock* cBlock,
cnct->p_cnct_operation = op_attach;
cnct->p_cnct_cversion = CONNECT_VERSION3;
cnct->p_cnct_client = ARCHITECTURE;
cnct->p_cnct_file.cstr_length = (ULONG) file_name.length();
cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(file_name.c_str());
const PathName& cnct_file(ref_db_name ? (*ref_db_name) : file_name);
cnct->p_cnct_file.cstr_length = (ULONG) cnct_file.length();
cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(cnct_file.c_str());
// If we want user verification, we can't speak anything less than version 7
@ -202,6 +205,7 @@ rem_port* WNET_analyze(ClntAuthBlock* cBlock,
switch (packet->p_operation)
{
case op_accept_data:
case op_cond_accept:
accept = &packet->p_acpd;
if (cBlock)
{

View File

@ -31,7 +31,8 @@ extern "C" {
#endif
rem_port* WNET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*, bool, Firebird::RefPtr<Config>*);
rem_port* WNET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*, bool,
Firebird::RefPtr<Config>*, const Firebird::PathName*);
rem_port* WNET_connect(const TEXT*, struct packet*, USHORT, Firebird::RefPtr<Config>*);
rem_port* WNET_reconnect(HANDLE);

View File

@ -192,7 +192,8 @@ static void xnet_log_error(const char* err_msg)
rem_port* XNET_analyze(ClntAuthBlock* cBlock,
const PathName& file_name,
bool uv_flag,
RefPtr<Config>* config)
RefPtr<Config>* config,
const Firebird::PathName* ref_db_name)
{
/**************************************
*
@ -244,8 +245,10 @@ rem_port* XNET_analyze(ClntAuthBlock* cBlock,
cnct->p_cnct_operation = op_attach;
cnct->p_cnct_cversion = CONNECT_VERSION3;
cnct->p_cnct_client = ARCHITECTURE;
cnct->p_cnct_file.cstr_length = (ULONG) file_name.length();
cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(file_name.c_str());
const PathName& cnct_file(ref_db_name ? (*ref_db_name) : file_name);
cnct->p_cnct_file.cstr_length = (ULONG) cnct_file.length();
cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(cnct_file.c_str());
cnct->p_cnct_user_id.cstr_length = (ULONG) user_id.getBufferLength();
cnct->p_cnct_user_id.cstr_address = user_id.getBuffer();
@ -287,6 +290,7 @@ rem_port* XNET_analyze(ClntAuthBlock* cBlock,
switch (packet->p_operation)
{
case op_accept_data:
case op_cond_accept:
accept = &packet->p_acpd;
if (cBlock)
{

View File

@ -32,7 +32,8 @@
#define rem_port void
#endif
rem_port* XNET_analyze(ClntAuthBlock*, const Firebird::PathName&, bool, Firebird::RefPtr<Config>*);
rem_port* XNET_analyze(ClntAuthBlock*, const Firebird::PathName&, bool, Firebird::RefPtr<Config>*,
const Firebird::PathName*);
rem_port* XNET_connect(struct packet*, USHORT, Firebird::RefPtr<Config>*);
rem_port* XNET_reconnect(ULONG);

View File

@ -339,6 +339,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
return P_TRUE(xdrs, p);
case op_accept_data:
case op_cond_accept:
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));

View File

@ -279,6 +279,8 @@ enum P_OP
op_crypt = 96,
op_crypt_key_callback = 97,
op_cond_accept = 98, // Server accepts connection, returns some data to client
// and asks client to continue authentication before attach call
op_max
};
@ -375,6 +377,7 @@ const UCHAR CNCT_specific_data = 7; // Some data, needed for user verification
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
const UCHAR CNCT_client_crypt = 11; // Client encyption level (DISABLED/ENABLED/REQUIRED)
// Accept Block (Server response to connect block)

View File

@ -59,11 +59,13 @@ 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,
const Firebird::string* dpb_config);
const Firebird::string* dpb_config = NULL);
void REMOTE_parseList(Remote::ParsedList&, Firebird::PathName);
void REMOTE_makeList(Firebird::PathName& list, const Remote::ParsedList& parsed);
void REMOTE_check_response(Firebird::IStatus* warning, Rdb* rdb, PACKET* packet, bool checkKeys = false);
extern signed char wcCompatible[3][3];
#define HANDSHAKE_DEBUG(A)
#define WIRECRYPT_DEBUG(A)

View File

@ -91,47 +91,25 @@ const ParametersSet spbParam =
isc_spb_config
};
const ParametersSet spbStartParam =
const ParametersSet connectParam =
{
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
0,
0,
0,
0,
0
};
const ParametersSet spbInfoParam =
{
0,
0,
isc_info_svc_auth_block,
0,
0,
0,
0,
CNCT_login,
0,
0,
0,
0,
CNCT_plugin_name,
CNCT_plugin_list,
CNCT_specific_data,
0,
0,
0,
0,
0,
0,
CNCT_host,
CNCT_user,
0
};
@ -1016,6 +994,32 @@ Firebird::PathName ClntAuthBlock::getPluginName()
return plugins.hasData() ? plugins.name() : "";
}
template <typename T>
static void addMutliPartConnectParameter(const T& dataToAdd,
Firebird::ClumpletWriter& user_id, UCHAR param)
{
size_t remaining = dataToAdd.getCount();
fb_assert(remaining <= 254u * 256u); // paranoid check => 65024
UCHAR part = 0;
UCHAR buffer[255];
typename T::const_pointer ptr = dataToAdd.begin();
while (remaining > 0)
{
size_t 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(param, buffer, step + 1);
if (!part) // we completed 256 loops, almost impossible but check anyway.
break;
}
}
void ClntAuthBlock::extractDataFromPluginTo(Firebird::ClumpletWriter& user_id)
{
// Add user login name
@ -1043,26 +1047,10 @@ void ClntAuthBlock::extractDataFromPluginTo(Firebird::ClumpletWriter& user_id)
// and we have no ways to override this limit cause it can be sent 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.
size_t remaining = dataFromPlugin.getCount();
fb_assert(remaining <= 254u * 256u); // paranoid check => 65024
UCHAR part = 0;
UCHAR buffer[255];
const UCHAR* ptr = dataFromPlugin.begin();
while (remaining > 0)
{
size_t step = remaining;
if (step > 254)
step = 254;
remaining -= step;
buffer[0] = part++;
fb_assert(part || remaining == 0);
memcpy(&buffer[1], ptr, step);
ptr += step;
addMutliPartConnectParameter(dataFromPlugin, user_id, CNCT_specific_data);
user_id.insertBytes(CNCT_specific_data, buffer, step + 1);
if (!part) // we completed 256 loops, almost impossible but check anyway.
break;
}
// Client's wirecrypt requested level
user_id.insertInt(CNCT_client_crypt, config->getWireCrypt(WC_CLIENT));
}
void ClntAuthBlock::resetClnt(const Firebird::PathName* fileName, const CSTRING* listStr)
@ -1086,8 +1074,8 @@ void ClntAuthBlock::resetClnt(const Firebird::PathName* fileName, const CSTRING*
dataForPlugin.clear();
dataFromPlugin.clear();
authComplete = false;
firstTime = true;
config = REMOTE_get_config(fileName, &dpbConfig);
pluginList = config->getPlugins(Firebird::PluginType::AuthClient);
@ -1144,17 +1132,21 @@ void ClntAuthBlock::storeDataForPlugin(unsigned int length, const unsigned char*
Firebird::RefPtr<Config> REMOTE_get_config(const Firebird::PathName* dbName,
const Firebird::string* dpb_config)
{
Firebird::RefPtr<Config> rc = Config::getDefaultConfig();
Firebird::RefPtr<Config> config;
if (dbName)
if (dbName && dbName->hasData())
{
Firebird::PathName dummy;
expandDatabaseName(*dbName, dummy, &rc);
expandDatabaseName(*dbName, dummy, &config);
}
else
{
config = Config::getDefaultConfig();
}
Config::merge(rc, dpb_config);
Config::merge(config, dpb_config);
return rc;
return config;
}
void REMOTE_parseList(Remote::ParsedList& parsed, Firebird::PathName list)
@ -1402,3 +1394,10 @@ bool rem_port::tryKeyType(const KnownServerKey& srvKey, InternalCryptKey* cryptK
return false;
}
signed char wcCompatible[3][3] = {
/* DISABLED ENABLED REQUIRED */
/* DISABLED */ {0, 0, -1},
/* ENABLED */ {0, 1, 1},
/* REQUIRED */ {-1, 1, 1}
};

View File

@ -116,22 +116,14 @@ struct ParametersSet
host_name, os_user, config_text;
};
extern const ParametersSet dpbParam, spbParam, spbStartParam, spbInfoParam;
extern const ParametersSet dpbParam, spbParam, connectParam;
struct Svc : public Firebird::GlobalStorage
{
ServService svc_iface; // service interface
Firebird::ClumpletWriter* svc_cached_spb; // Saved auth tags from attachService() call
Firebird::Array<UCHAR> svc_wide_auth; // Server-wide (default) authentication block
enum {
SVCAUTH_NONE, // Service is not authenticated
SVCAUTH_TEMP, // Service is authenticated for single task
SVCAUTH_PERM // Service is authenticated permanently
} svc_auth; // Authentication state of service
Svc() :
svc_iface(NULL), svc_cached_spb(NULL),
svc_wide_auth(getPool()), svc_auth(SVCAUTH_NONE)
svc_iface(NULL)
{ }
};
@ -580,8 +572,14 @@ typedef Firebird::Array<rem_que_packet> PacketQueue;
class ServerAuthBase
{
public:
enum AuthenticateFlags {
NO_FLAGS = 0x0,
CONT_AUTH = 0x1,
USE_COND_ACCEPT = 0x2
};
virtual ~ServerAuthBase();
virtual bool authenticate(PACKET* send, bool cont = false) = 0;
virtual bool authenticate(PACKET* send, AuthenticateFlags flags = NO_FLAGS) = 0;
};
class ServerCallbackBase
@ -668,8 +666,6 @@ public:
void extractDataFromPluginTo(Firebird::ClumpletWriter& user_id);
void resetClnt(const Firebird::PathName* fileName, const CSTRING* listStr = NULL);
bool checkPluginName(Firebird::PathName& nameToCheck);
void saveServiceDataTo(rem_port*);
void loadServiceDataFrom(rem_port*);
Firebird::PathName getPluginName();
void tryNewKeys(rem_port*);
void releaseKeys(unsigned from);
@ -696,7 +692,6 @@ private:
Firebird::PathName pluginName, pluginList;
// These two may be legacy encrypted password, trusted auth data and so on
Firebird::UCharBuffer dataForPlugin, dataFromPlugin;
Firebird::PathName dbPath;
Firebird::ClumpletWriter lastExtractedKeys;
Firebird::ObjectsArray<Firebird::PathName> newKeys;
bool flComplete, firstTime;
@ -709,7 +704,6 @@ public:
: port(p_port),
userName(getPool()), pluginName(getPool()), pluginList(getPool()),
dataForPlugin(getPool()), dataFromPlugin(getPool()),
dbPath(getPool()),
lastExtractedKeys(getPool(), Firebird::ClumpletReader::UnTagged, MAX_DPB_SIZE),
newKeys(getPool()),
flComplete(false), firstTime(true),
@ -723,10 +717,9 @@ public:
void extractDataFromPluginTo(cstring* to);
void extractDataFromPluginTo(P_AUTH_CONT* to);
void extractDataFromPluginTo(P_ACPD* to);
bool authCompleted(bool flag = false);
void setPath(const Firebird::PathName* dbPath);
void setLogin(const Firebird::string& user);
const char* getPath();
void load(Firebird::ClumpletReader& userId);
const char* getPluginName();
void setPluginList(const Firebird::string& name);
@ -864,7 +857,7 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted
rem_str* port_host; // Our name
rem_str* port_connection; // Name of connection
Firebird::string port_login;
Firebird::string port_password;
Firebird::PathName port_security_db;
Firebird::string port_user_name;
Firebird::string port_peer_name;
Firebird::string port_protocol_id; // String containing protocol name for this port
@ -888,6 +881,7 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted
// requires wire crypt active before attachDatabase()
bool port_crypt_complete; // wire crypt init is complete one way or another,
// up to being turned off in firebird.conf
bool port_required_encryption; // encryption is required on port
Firebird::ObjectsArray<KnownServerKey> port_known_server_keys; // Server sends to client
// keys known by it, they are stored here
Firebird::IWireCryptPlugin* port_crypt_plugin; // plugin used by port, when not NULL - crypts wire data
@ -916,7 +910,7 @@ public:
port_packet_vector(0),
#endif
port_objects(getPool()), port_version(0), port_host(0),
port_connection(0), port_login(getPool()), port_password(getPool()),
port_connection(0), port_login(getPool()), port_security_db(getPool()),
port_user_name(getPool()), port_peer_name(getPool()),
port_protocol_id(getPool()), port_address(getPool()),
port_rpr(0), port_statement(0), port_receive_rmtque(0),
@ -924,6 +918,7 @@ public:
port_queue(getPool()), port_qoffset(0),
port_srv_auth(NULL), port_srv_auth_block(NULL),
port_crypt_keys(getPool()), port_need_disk_crypt(false), port_crypt_complete(false),
port_required_encryption(true), // safe default
port_known_server_keys(getPool()), port_crypt_plugin(NULL),
port_client_crypt_callback(NULL), port_server_crypt_callback(NULL),
port_buffer(FB_NEW(getPool()) UCHAR[rpt])
@ -1101,7 +1096,7 @@ public:
{
return send_response(p, obj, length, status->get(), defer_flag);
}
ISC_STATUS service_attach(const char*, Firebird::ClumpletWriter*, PACKET*, bool);
ISC_STATUS service_attach(const char*, Firebird::ClumpletWriter*, PACKET*);
ISC_STATUS service_end(P_RLSE*, PACKET*);
void service_start(P_INFO*, PACKET*);
ISC_STATUS set_cursor(P_SQLCUR*, PACKET*);

File diff suppressed because it is too large Load Diff

View File

@ -312,6 +312,7 @@ const SvcSwitches attSwitch[] =
{"password", putStringArgument, 0, isc_spb_password, 0},
{"fetch_password", putFileArgument, 0, isc_spb_password, 0},
{"trusted_auth", putSingleTag, 0, isc_spb_trusted_auth, 0},
{"expected_db", putStringArgument, 0, isc_spb_expected_db, 0},
{0, 0, 0, 0, 0}
};

View File

@ -300,7 +300,7 @@ int gsec(Firebird::UtilSvc* uSvc)
manager = getPlugin.plugin();
if (!manager)
{
GSEC_error_redirect((Firebird::Arg::Gds(isc_random) << "Missing management plugin").value(), GsecMsg15);
GSEC_error_redirect((Firebird::Arg::Gds(isc_random) << "Management plugin is missing or failed to load").value(), GsecMsg15);
}
GsecInfo info(user_data->trustedUser.get(), user_data->role.get(),

View File

@ -450,22 +450,15 @@ public:
Firebird::StatusHolder savedStatus; // Do not use raise() method of this class in yValve.
};
class YService : public Firebird::StdPlugin<Firebird::IService, FB_SERVICE_VERSION>, public YObject, public EnterCount
class YService : public YHelper<YService, Firebird::IService, FB_SERVICE_VERSION>, public EnterCount
{
public:
static const ISC_STATUS ERROR_CODE = isc_bad_svc_handle;
static const int SERV_START = 1;
static const int SERV_QUERY = 2;
static const int SERV_DETACH = 3;
// Regular case
YService(Firebird::IProvider* aProvider, Firebird::IService* aNext, bool utf8);
// Used when next handle creation is delayed till service start
YService(const char* svcName, unsigned int spbLength, const unsigned char* spb,
Firebird::ICryptKeyCallback* callback, bool utf8);
~YService();
void shutdown();
void destroy();
FB_API_HANDLE& getHandle();
@ -479,54 +472,13 @@ public:
unsigned int spbLength, const unsigned char* spb);
public:
class ServiceType
{
public:
Firebird::IProvider* provider;
Firebird::RefPtr<Firebird::IService> next;
public:
ServiceType(Firebird::IService* n, Firebird::IProvider* p)
: provider(p), next(n)
{ }
ServiceType()
: provider(NULL)
{ }
~ServiceType();
void shutdown();
void detach(Firebird::IStatus* status);
};
ServiceType regular, started, queryCache;
Firebird::PathName attachName;
Firebird::AutoPtr<Firebird::ClumpletWriter> attachSpb;
int FB_CARG release();
typedef IService NextInterface;
typedef YService YRef;
void shutdown()
{
regular.shutdown();
started.shutdown();
queryCache.shutdown();
}
Firebird::IService* getNextService(int mode, Firebird::IStatus* status);
private:
unsigned int checkSpbLen;
const unsigned char* checkSpbPresent;
Firebird::HalfStaticArray<UCHAR, 256> authBlock;
Firebird::IProvider* provider;
Firebird::ICryptKeyCallback* cryptCallback;
bool utf8Connection; // Client talks to us using UTF8, else - system default charset
void populateSpb(Firebird::ClumpletWriter& spb, UCHAR tag);
};
class Dispatcher : public Firebird::StdPlugin<Firebird::IProvider, FB_PROVIDER_VERSION>

View File

@ -2145,10 +2145,10 @@ static int load(ISC_QUAD* blob_id, FB_API_HANDLE database, FB_API_HANDLE transac
// new utl
static inline void setTag(Firebird::ClumpletWriter& dpb, UCHAR tag,
Firebird::string& value, bool utf8)
static void setTag(Firebird::ClumpletWriter& dpb, UCHAR tag, const char* env, bool utf8)
{
if (! dpb.find(tag))
Firebird::string value;
if (fb_utils::readenv(env, value) && (!dpb.find(tag)))
{
if (utf8)
{
@ -2169,16 +2169,15 @@ void setLogin(Firebird::ClumpletWriter& dpb, bool spbFlag)
if (!(dpb.find(trusted_auth) || dpb.find(address_path) || dpb.find(auth_block)))
{
bool utf8 = dpb.find(utf8Tag);
Firebird::string username;
if (fb_utils::readenv(ISC_USER, username))
{
setTag(dpb, isc_dpb_user_name, username, utf8);
}
Firebird::string password;
if (fb_utils::readenv(ISC_PASSWORD, password) && !dpb.find(isc_dpb_password))
setTag(dpb, isc_dpb_user_name, ISC_USER, utf8);
if (!dpb.find(isc_dpb_password_enc))
{
setTag(dpb, isc_dpb_password, password, utf8);
setTag(dpb, isc_dpb_password, ISC_PASSWORD, utf8);
}
if (spbFlag)
{
setTag(dpb, isc_spb_expected_db, "FB_EXPECTED_DB", utf8);
}
}
}

View File

@ -782,13 +782,13 @@ namespace Why
}
template <>
YEntry<YService>::YEntry(IStatus* aStatus, YService* aService, int mode)
YEntry<YService>::YEntry(IStatus* aStatus, YService* aService, int checkService)
: ref(aService), nextRef(NULL)
{
aStatus->init();
init(aService->getNextService(mode, aStatus));
init(aService->next);
if ((mode != YService::SERV_DETACH) && !(nextRef.hasData()))
if (checkService && !(nextRef.hasData()))
{
fini();
Arg::Gds(YService::ERROR_CODE).raise();
@ -5007,195 +5007,54 @@ void YAttachment::getNextTransaction(IStatus* status, ITransaction* tra, NextTra
//-------------------------------------
static IService* getServiceManagerByName(IProvider** provider, IStatus* status,
const char* serviceName, unsigned int spbLength, const unsigned char* spb,
Firebird::ICryptKeyCallback* cryptCallback)
{
RefPtr<Config> config(Config::getDefaultConfig());
ClumpletReader readSpb(ClumpletReader::spbList, spb, spbLength);
if (readSpb.find(isc_spb_config))
{
string spb_config;
readSpb.getString(spb_config);
Config::merge(config, &spb_config);
}
for (GetPlugins<IProvider> providerIterator(PluginType::Provider,
FB_PROVIDER_VERSION, upInfo, config);
providerIterator.hasData();
providerIterator.next())
{
IProvider* p = providerIterator.plugin();
if (cryptCallback)
{
p->setDbCryptCallback(status, cryptCallback);
if (!status->isSuccess())
continue;
}
IService* service = p->attachServiceManager(status, serviceName, spbLength, spb);
if (status->isSuccess())
{
if (provider)
{
p->addRef();
*provider = p;
}
return service;
}
}
if (status->isSuccess())
{
(Arg::Gds(isc_service_att_err) <<
Arg::Gds(isc_no_providers)).copyTo(status);
}
return NULL;
}
YService::ServiceType::~ServiceType()
{
if (provider)
{
PluginManagerInterfacePtr()->releasePlugin(provider);
provider = NULL;
}
}
void YService::ServiceType::shutdown()
{
if (provider)
{
next = NULL;
PluginManagerInterfacePtr()->releasePlugin(provider);
provider = NULL;
}
}
void YService::ServiceType::detach(IStatus* status)
{
if (next.hasData())
{
next->detach(status);
if (!status->isSuccess())
{
status_exception::raise(status->get());
}
}
}
YService::YService(IProvider* aProvider, IService* aNext, bool utf8)
: regular(aNext, aProvider),
attachName(getPool()),
checkSpbLen(0),
checkSpbPresent(NULL),
authBlock(getPool()),
: YHelper<YService, Firebird::IService, FB_SERVICE_VERSION>(aNext),
provider(aProvider),
cryptCallback(NULL),
utf8Connection(utf8)
{
this->addRef(); // from YHelper
provider->addRef();
makeHandle(&services, this, handle);
}
YService::YService(const char* svcName, unsigned int spbLength, const unsigned char* spb,
ICryptKeyCallback* callback, bool utf8)
: attachName(getPool()),
attachSpb(FB_NEW(getPool()) ClumpletWriter(getPool(), ClumpletReader::spbList,
MAX_DPB_SIZE, spb, spbLength)),
checkSpbLen(0),
checkSpbPresent(NULL),
authBlock(getPool()),
cryptCallback(callback),
utf8Connection(utf8)
{
attachName.assign(svcName);
this->addRef(); // from YHelper
makeHandle(&services, this, handle);
if (attachSpb->find(isc_spb_auth_block))
authBlock.add(attachSpb->getBytes(), attachSpb->getClumpLength());
}
FB_API_HANDLE& YService::getHandle()
{
fb_assert(handle);
return handle;
}
IService* YService::getNextService(int mode, IStatus* status)
{
if (regular.next)
return regular.next;
switch (mode)
{
case SERV_START:
if (started.provider)
started.shutdown();
started.next = getServiceManagerByName(&started.provider, status, attachName.c_str(),
(attachSpb ? attachSpb->getBufferLength() : 0),
(attachSpb ? attachSpb->getBuffer() : NULL), cryptCallback);
if (!status->isSuccess())
status_exception::raise(status->get());
return started.next;
case SERV_QUERY:
if (fb_utils::isRunningCheck(checkSpbPresent, checkSpbLen))
return started.next;
if (queryCache.next)
return queryCache.next;
queryCache.next = getServiceManagerByName(&queryCache.provider, status, attachName.c_str(),
(attachSpb ? attachSpb->getBufferLength() : 0),
(attachSpb ? attachSpb->getBuffer() : NULL), cryptCallback);
if (!status->isSuccess())
status_exception::raise(status->get());
return queryCache.next;
case SERV_DETACH:
break;
default:
fb_assert(false);
}
return NULL;
}
YService::~YService()
{
if (provider)
PluginManagerInterfacePtr()->releasePlugin(provider);
}
void YService::destroy()
{
removeHandle(&services, handle);
regular.next = NULL;
started.next = NULL;
queryCache.next = NULL;
next = NULL;
release();
}
void YService::shutdown()
{
if (provider)
{
destroy();
PluginManagerInterfacePtr()->releasePlugin(provider);
provider = NULL;
}
}
void YService::detach(IStatus* status)
{
try
{
YEntry<YService> entry(status, this, SERV_DETACH);
YEntry<YService> entry(status, this, 1);
regular.detach(status);
started.detach(status);
queryCache.detach(status);
if (entry.next())
entry.next()->detach(status);
destroy();
}
@ -5205,44 +5064,18 @@ void YService::detach(IStatus* status)
}
}
void YService::populateSpb(ClumpletWriter& spb, UCHAR tag)
{
if (attachSpb)
attachSpb->deleteWithTag(isc_spb_auth_block);
else
attachSpb = FB_NEW(getPool()) ClumpletWriter(getPool(), ClumpletReader::spbList, MAX_DPB_SIZE);
if (spb.find(tag))
{
attachSpb->insertBytes(isc_spb_auth_block, spb.getBytes(), spb.getClumpLength());
spb.deleteClumplet();
}
else
attachSpb->insertTag(isc_spb_auth_block);
}
void YService::query(IStatus* status, unsigned int sendLength, const unsigned char* sendItems,
unsigned int receiveLength, const unsigned char* receiveItems,
unsigned int bufferLength, unsigned char* buffer)
{
try
{
ClumpletWriter spb(ClumpletReader::SpbSendItems, MAX_DPB_SIZE, sendItems, sendLength);
if (!regular.next)
populateSpb(spb, isc_info_svc_auth_block);
checkSpbLen = receiveLength;
checkSpbPresent = receiveItems;
YEntry<YService> entry(status, this, SERV_QUERY);
entry.next()->query(status, spb.getBufferLength(), spb.getBuffer(),
YEntry<YService> entry(status, this);
entry.next()->query(status, sendLength, sendItems,
receiveLength, receiveItems, bufferLength, buffer);
checkSpbLen = 0;
checkSpbPresent = NULL;
}
catch (const Exception& e)
{
checkSpbLen = 0;
checkSpbPresent = NULL;
e.stuffException(status);
}
}
@ -5252,16 +5085,12 @@ void YService::start(IStatus* status, unsigned int spbLength, const unsigned cha
try
{
ClumpletWriter spb(ClumpletReader::SpbStart, MAX_DPB_SIZE, spbItems, spbLength);
if (!regular.next)
{
populateSpb(spb, isc_spb_auth_block);
}
if (!utf8Connection)
{
IntlSpbStart().toUtf8(spb, 0);
}
YEntry<YService> entry(status, this, SERV_START);
YEntry<YService> entry(status, this);
entry.next()->start(status, spb.getBufferLength(), spb.getBuffer());
}
catch (const Exception& e)
@ -5270,25 +5099,6 @@ void YService::start(IStatus* status, unsigned int spbLength, const unsigned cha
}
}
int YService::release()
{
if (--this->refCounter == 0)
{
if (regular.next || started.next || queryCache.next)
{
++this->refCounter; // to be decremented in destroy()
++this->refCounter; // to avoid recursion
this->destroy(); // destroy() must call release()
--this->refCounter;
}
delete this; // call correct destructor !
return 0;
}
return 1;
}
//-------------------------------------
@ -5424,7 +5234,6 @@ YService* Dispatcher::attachServiceManager(IStatus* status, const char* serviceN
unsigned int spbLength, const unsigned char* spb)
{
IService* service = NULL;
try
{
DispatcherEntry entry(status);
@ -5448,20 +5257,41 @@ YService* Dispatcher::attachServiceManager(IStatus* status, const char* serviceN
IntlSpb().toUtf8(spbWriter, isc_spb_utf8_filename);
}
if ((spbWriter.find(isc_spb_auth_block) && spbWriter.getClumpLength() > 0) ||
ISC_check_if_remote(svcName, false))
// Build correct config
RefPtr<Config> config(Config::getDefaultConfig());
if (spbWriter.find(isc_spb_config))
{
IProvider* provider = NULL;
service = getServiceManagerByName(&provider, status, svcName.c_str(),
spbWriter.getBufferLength(), spbWriter.getBuffer(), cryptCallback);
if (service)
return new YService(provider, service, utfData);
string spb_config;
spbWriter.getString(spb_config);
Config::merge(config, &spb_config);
}
else
for (GetPlugins<IProvider> providerIterator(PluginType::Provider,
FB_PROVIDER_VERSION, upInfo, config);
providerIterator.hasData();
providerIterator.next())
{
return new YService(svcName.c_str(), spbWriter.getBufferLength(),
spbWriter.getBuffer(), cryptCallback, utfData);
IProvider* p = providerIterator.plugin();
if (cryptCallback)
{
p->setDbCryptCallback(status, cryptCallback);
if (!status->isSuccess())
continue;
}
service = p->attachServiceManager(status, svcName.c_str(),
spbWriter.getBufferLength(), spbWriter.getBuffer());
if (status->isSuccess())
{
return new YService(p, service, utfData);
}
}
if (status->isSuccess())
{
(Arg::Gds(isc_service_att_err) <<
Arg::Gds(isc_no_providers)).copyTo(status);
}
}
catch (const Exception& e)