Skip to content

Commit

Permalink
Implemented CORE-5883: Services version 1 cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexPeshkoff committed Aug 1, 2018
1 parent bc0f26a commit 71b6315
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 315 deletions.
4 changes: 2 additions & 2 deletions src/common/isc_f_proto.h
Expand Up @@ -35,9 +35,9 @@ enum iscProtocol {ISC_PROTOCOL_LOCAL, ISC_PROTOCOL_TCPIP, ISC_PROTOCOL_WLAN};
#ifndef NO_NFS
bool ISC_analyze_nfs(Firebird::PathName&, Firebird::PathName&);
#endif
bool ISC_analyze_protocol(const char*, Firebird::PathName&, Firebird::PathName&, const char*);
bool ISC_analyze_protocol(const char*, Firebird::PathName&, Firebird::PathName&, const char*, bool needFile);
bool ISC_analyze_pclan(Firebird::PathName&, Firebird::PathName&);
bool ISC_analyze_tcp(Firebird::PathName&, Firebird::PathName&);
bool ISC_analyze_tcp(Firebird::PathName&, Firebird::PathName&, bool = true);
bool ISC_check_if_remote(const Firebird::PathName&, bool);
iscProtocol ISC_extract_host(Firebird::PathName&, Firebird::PathName&, bool);
bool ISC_expand_filename(Firebird::PathName&, bool);
Expand Down
17 changes: 12 additions & 5 deletions src/common/isc_file.cpp
Expand Up @@ -347,7 +347,7 @@ bool ISC_analyze_nfs(tstring& expanded_filename, tstring& node_name)


bool ISC_analyze_protocol(const char* protocol, tstring& expanded_name, tstring& node_name,
const char* separator)
const char* separator, bool need_file)
{
/**************************************
*
Expand All @@ -367,14 +367,15 @@ bool ISC_analyze_protocol(const char* protocol, tstring& expanded_name, tstring&
if (expanded_name.find(prefix) != 0)
return false;

PathName savedName = expanded_name;
expanded_name.erase(0, prefix.length());

if (separator) // this implies node name is expected!
{
size p = expanded_name.find_first_of('/');
if (p != 0 && p != npos)
if (p != 0)
{
node_name = expanded_name.substr(0, p);
node_name = p == npos ? expanded_name : expanded_name.substr(0, p);
expanded_name.erase(0, node_name.length() + 1);

if (node_name[0] == '[')
Expand All @@ -392,6 +393,12 @@ bool ISC_analyze_protocol(const char* protocol, tstring& expanded_name, tstring&
}
}

if (need_file && !expanded_name.hasData())
{
expanded_name = savedName;
return false;
}

return true;
}

Expand Down Expand Up @@ -447,7 +454,7 @@ bool ISC_analyze_pclan(tstring& expanded_name, tstring& node_name)
#endif // WIN_NT


bool ISC_analyze_tcp(tstring& file_name, tstring& node_name)
bool ISC_analyze_tcp(tstring& file_name, tstring& node_name, bool need_file)
{
/**************************************
*
Expand Down Expand Up @@ -482,7 +489,7 @@ bool ISC_analyze_tcp(tstring& file_name, tstring& node_name)
else
p = file_name.find(INET_FLAG);

if (p == npos || p == 0 || p == file_name.length() - 1)
if (p == npos || p == 0 || (need_file && (p == file_name.length() - 1)))
return false;

node_name = file_name.substr(0, p);
Expand Down
4 changes: 2 additions & 2 deletions src/jrd/Mapping.cpp
Expand Up @@ -739,8 +739,8 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject
if (!ISC_check_process_existence(p->id))
{
p->flags &= ~MappingHeader::FLAG_ACTIVE;
sharedMemory->eventFini(&sMem->process[process].notifyEvent);
sharedMemory->eventFini(&sMem->process[process].callbackEvent);
sharedMemory->eventFini(&p->notifyEvent);
sharedMemory->eventFini(&p->callbackEvent);
break;
}
}
Expand Down
182 changes: 84 additions & 98 deletions src/jrd/svc.cpp
Expand Up @@ -65,9 +65,6 @@

#include "../common/classes/DbImplementation.h"

// Services table.
#include "../jrd/svc_tab.h"

// The switches tables. Needed only for utilities that run as service, too.
#include "../common/classes/Switches.h"
#include "../alice/aliceswi.h"
Expand All @@ -78,6 +75,15 @@
#include "../jrd/trace/traceswi.h"
#include "../jrd/val_proto.h"

// Service threads
#include "../burp/burp_proto.h"
#include "../alice/alice_proto.h"
int main_gstat(Firebird::UtilSvc* uSvc);
#include "../utilities/nbackup/nbk_proto.h"
#include "../utilities/gsec/gsec_proto.h"
#include "../jrd/trace/TraceService.h"
#include "../jrd/val_proto.h"

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
Expand Down Expand Up @@ -202,6 +208,35 @@ namespace {

using namespace Jrd;

namespace {
const serv_entry services[] =
{
{ isc_action_svc_backup, "Backup Database", BURP_main },
{ isc_action_svc_restore, "Restore Database", BURP_main },
{ isc_action_svc_repair, "Repair Database", ALICE_main },
{ isc_action_svc_add_user, "Add User", GSEC_main },
{ isc_action_svc_delete_user, "Delete User", GSEC_main },
{ isc_action_svc_modify_user, "Modify User", GSEC_main },
{ isc_action_svc_display_user, "Display User", GSEC_main },
{ isc_action_svc_properties, "Database Properties", ALICE_main },
{ isc_action_svc_db_stats, "Database Stats", main_gstat },
{ isc_action_svc_get_fb_log, "Get Log File", Service::readFbLog },
{ isc_action_svc_nbak, "Incremental Backup Database", NBACKUP_main },
{ isc_action_svc_nrest, "Incremental Restore Database", NBACKUP_main },
{ isc_action_svc_trace_start, "Start Trace Session", TRACE_main },
{ isc_action_svc_trace_stop, "Stop Trace Session", TRACE_main },
{ isc_action_svc_trace_suspend, "Suspend Trace Session", TRACE_main },
{ isc_action_svc_trace_resume, "Resume Trace Session", TRACE_main },
{ isc_action_svc_trace_list, "List Trace Sessions", TRACE_main },
{ isc_action_svc_set_mapping, "Set Domain Admins Mapping to RDB$ADMIN", GSEC_main },
{ isc_action_svc_drop_mapping, "Drop Domain Admins Mapping to RDB$ADMIN", GSEC_main },
{ isc_action_svc_display_user_adm, "Display User with Admin Info", GSEC_main },
{ isc_action_svc_validate, "Validate Database", VAL_service},
{ 0, NULL, NULL }
};

}

Service::Validate::Validate(Service* svc)
: sharedGuard(globalServicesMutex, FB_FUNCTION)
{
Expand Down Expand Up @@ -703,7 +738,7 @@ namespace
Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_data,
Firebird::ICryptKeyCallback* crypt_callback)
: svc_status(getPool()), svc_parsed_sw(getPool()),
svc_stdout_head(0), svc_stdout_tail(0), svc_service(NULL), svc_service_run(NULL),
svc_stdout_head(0), svc_stdout_tail(0), svc_service_run(NULL),
svc_resp_alloc(getPool()), svc_resp_buf(0), svc_resp_ptr(0), svc_resp_buf_len(0),
svc_resp_len(0), svc_flags(SVC_finished), svc_user_flag(0), svc_spb_version(0),
svc_do_shutdown(false), svc_shutdown_in_progress(false), svc_timeout(false),
Expand Down Expand Up @@ -732,35 +767,15 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
// Since this moment we should remove this service from allServices in case of error thrown
try
{
#ifdef DEV_BUILD
// If the service name begins with a slash, ignore it.
if (*service_name == '/' || *service_name == '\\') {
if (*service_name == '/' || *service_name == '\\')
service_name++;
}

// Find the service by looking for an exact match.
string svcname(service_name);

#ifdef DEV_BUILD
if (svcname == "@@@")
{
svc_debug = true;
svcname = "service_mgr";
}
#endif

const serv_entry* serv;
for (serv = services; serv->serv_name; serv++)
{
if (svcname == serv->serv_name)
break;
}

if (!serv->serv_name)
{
status_exception::raise(Arg::Gds(isc_service_att_err) <<
Arg::Gds(isc_svcnotdef) << Arg::Str(svcname));
}

// Process the service parameter block.
ClumpletReader spb(ClumpletReader::spbList, spb_data, spb_length, spbVersionError);
dumpAuthBlock("Jrd::Service() ctor", &spb, isc_spb_auth_block);
Expand All @@ -771,92 +786,68 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
{
svc_trace_manager = FB_NEW_POOL(*getDefaultMemoryPool()) TraceManager(this);
svc_user_flag = SVC_user_dba;
svc_service = serv;
return;
}
#endif

// Perhaps checkout the user in the security database.
USHORT user_flag;
if (!strcmp(serv->serv_name, "anonymous")) {
user_flag = SVC_user_none;
}
else
USHORT user_flag = 0;

if (!svc_username.hasData())
{
if (!svc_username.hasData())
if (svc_auth_block.hasData())
{
if (svc_auth_block.hasData())
{
// remote connection - use svc_auth_block
PathName dummy;
RefPtr<const Config> config;
expandDatabaseName(svc_expected_db, dummy, &config);

Mapping mapping(Mapping::MAP_THROW_NOT_FOUND, svc_crypt_callback);
mapping.needAuthBlock(svc_auth_block);

mapping.setAuthBlock(svc_auth_block);
mapping.setErrorMessagesContextName("services manager");
mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr);

string trusted_role;
mapping.mapUser(svc_username, trusted_role);
trusted_role.upper();
svc_trusted_role = trusted_role == ADMIN_ROLE;
}
else
{
// we have embedded service connection, check OS auth
if (ISC_get_user(&svc_username, NULL, NULL))
{
svc_username = DBA_USER_NAME;
}
}
}
// remote connection - use svc_auth_block
PathName dummy;
RefPtr<const Config> config;
expandDatabaseName(svc_expected_db, dummy, &config);

if (!svc_username.hasData())
{
// user name and password are required while
// attaching to the services manager
status_exception::raise(Arg::Gds(isc_service_att_err) << Arg::Gds(isc_svcnouser));
}
Mapping mapping(Mapping::MAP_THROW_NOT_FOUND, svc_crypt_callback);
mapping.needAuthBlock(svc_auth_block);

if (svc_username.length() > USERNAME_LENGTH)
{
status_exception::raise(Arg::Gds(isc_long_login) <<
Arg::Num(svc_username.length()) << Arg::Num(USERNAME_LENGTH));
}
mapping.setAuthBlock(svc_auth_block);
mapping.setErrorMessagesContextName("services manager");
mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr);

// Check that the validated user has the authority to access this service
if (svc_username != DBA_USER_NAME && !svc_trusted_role) {
user_flag = SVC_user_any;
string trusted_role;
mapping.mapUser(svc_username, trusted_role);
trusted_role.upper();
svc_trusted_role = trusted_role == ADMIN_ROLE;
}
else {
user_flag = SVC_user_dba | SVC_user_any;
else
{
// we have embedded service connection, check OS auth
if (ISC_get_user(&svc_username, NULL, NULL))
svc_username = DBA_USER_NAME;
}
}

// move service switches in
string switches;
if (serv->serv_std_switches)
switches = serv->serv_std_switches;
if (svc_command_line.hasData() && serv->serv_std_switches)
switches += ' ';
switches += svc_command_line;
if (!svc_username.hasData())
{
// user name and password are required while
// attaching to the services manager
status_exception::raise(Arg::Gds(isc_service_att_err) << Arg::Gds(isc_svcnouser));
}

if (svc_username.length() > USERNAME_LENGTH)
{
status_exception::raise(Arg::Gds(isc_long_login) <<
Arg::Num(svc_username.length()) << Arg::Num(USERNAME_LENGTH));
}

// Check that the validated user has the authority to access this service
if (svc_username != DBA_USER_NAME && !svc_trusted_role)
user_flag = SVC_user_any;
else
user_flag = SVC_user_dba | SVC_user_any;

// move service switches in
string switches = svc_command_line;
svc_flags |= switches.hasData() ? SVC_cmd_line : 0;
svc_perm_sw = switches;
svc_user_flag = user_flag;
svc_service = serv;

svc_trace_manager = FB_NEW_POOL(*getDefaultMemoryPool()) TraceManager(this);

// If an executable is defined for the service, try to fork a new thread.
// Only do this if we are working with a version 1 service
if (serv->serv_thd && svc_spb_version == isc_spb_version1)
{
start(serv);
}
} // try
catch (const Firebird::Exception& ex)
{
Expand Down Expand Up @@ -2266,11 +2257,6 @@ void Service::start(const serv_entry* service_run)
// Break up the command line into individual arguments.
parseSwitches();

if (svc_service && svc_service->serv_name)
{
argv[0] = svc_service->serv_name;
}

svc_service_run = service_run;
Thread::start(run, this, THREAD_medium);
}
Expand Down Expand Up @@ -3224,7 +3210,7 @@ bool Service::get_action_svc_parameter(UCHAR action,

const char* Service::getServiceMgr() const
{
return svc_service ? svc_service->serv_name : NULL;
return "service_mgr";
}

const char* Service::getServiceName() const
Expand Down
16 changes: 9 additions & 7 deletions src/jrd/svc.h
Expand Up @@ -43,12 +43,6 @@
#include "../burp/split/spit.h"
#include "../jrd/status.h"

// forward decl.

namespace Jrd {
struct serv_entry;
}

namespace Firebird {
namespace Arg {
class StatusVector;
Expand All @@ -57,6 +51,15 @@ namespace Firebird {

namespace Jrd {

typedef int ServiceEntry(Firebird::UtilSvc*);

struct serv_entry
{
USHORT serv_action; // isc_action_svc_....
const TEXT* serv_name; // service name
ServiceEntry* serv_thd; // thread to execute
};

const ULONG SERVICE_VERSION = 2;

const int SVC_STDOUT_BUFFER_SIZE = 1024;
Expand Down Expand Up @@ -284,7 +287,6 @@ class Service : public Firebird::UtilSvc, public TypedHandle<type_svc>
ULONG svc_stdout_tail;
UCHAR svc_stdout[SVC_STDOUT_BUFFER_SIZE]; // output from service
Firebird::Semaphore svcStart;
const serv_entry* svc_service; // attached service's entry
const serv_entry* svc_service_run; // running service's entry
Firebird::Array<UCHAR> svc_resp_alloc;
UCHAR* svc_resp_buf;
Expand Down

1 comment on commit 71b6315

@hvlad
Copy link
Member

@hvlad hvlad commented on 71b6315 Aug 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like after this change some loopback connection strings stop working:

F:\FB2\fb40\temp\x64\Debug\firebird>isql inet://s:\Temp\Z40.FDB
Statement failed, SQLSTATE = 08006
Unable to complete network request to host "inet".
-Failed to locate host machine.
-The specified name was not found in the hosts file or Domain Name Services.
Use CONNECT or CREATE DATABASE to specify a database
SQL> exit;

F:\FB2\fb40\temp\x64\Debug\firebird>
F:\FB2\fb40\temp\x64\Debug\firebird>isql wnet://s:\Temp\Z40.FDB
Statement failed, SQLSTATE = 08006
Unable to complete network request to host "wnet".
-Failed to locate host machine.
-The specified name was not found in the hosts file or Domain Name Services.
Use CONNECT or CREATE DATABASE to specify a database
SQL> exit;

F:\FB2\fb40\temp\x64\Debug\firebird>isql xnet://s:\Temp\Z40.FDB
Database: xnet://s:\Temp\Z40.FDB, User: SYSDBA

Please sign in to comment.