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:
parent
61d5a49c93
commit
5a054cca16
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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},
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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}
|
||||
};
|
||||
|
@ -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
@ -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}
|
||||
};
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user