예제 #1
0
// create directory for lock files and set appropriate access rights
void createLockDirectory(const char* pathname)
{
	static bool errorLogged = false;

	DWORD attr = GetFileAttributes(pathname);
	DWORD errcode = 0;
	if (attr == INVALID_FILE_ATTRIBUTES)
	{
		errcode = GetLastError();
		if (errcode == ERROR_FILE_NOT_FOUND)
		{
			if (!CreateDirectory(pathname, NULL)) {
				errcode = GetLastError();
			}
			else
			{
				adjustLockDirectoryAccess(pathname);

				attr = GetFileAttributes(pathname);
				if (attr == INVALID_FILE_ATTRIBUTES) {
					errcode = GetLastError();
				}
			}
		}
	}

	Firebird::string err;
	if (attr == INVALID_FILE_ATTRIBUTES)
	{
		err.printf("Can't create directory \"%s\". OS errno is %d", pathname, errcode);
		if (!errorLogged)
		{
			errorLogged = true;
			gds__log(err.c_str());
		}
		Firebird::fatal_exception::raise(err.c_str());
	}

	if (!(attr & FILE_ATTRIBUTE_DIRECTORY))
	{
		err.printf("Can't create directory \"%s\". File with same name already exists", pathname);
		if (!errorLogged)
		{
			errorLogged = true;
			gds__log(err.c_str());
		}
		Firebird::fatal_exception::raise(err.c_str());
	}

	if (attr & FILE_ATTRIBUTE_READONLY)
	{
		err.printf("Can't create directory \"%s\". Readonly directory with same name already exists", pathname);
		if (!errorLogged)
		{
			errorLogged = true;
			gds__log(err.c_str());
		}
		Firebird::fatal_exception::raise(err.c_str());
	}
}
예제 #2
0
	void grantRevokeAdmin(Firebird::IUser* user, bool ignoreRevoke = false)
	{
		if (!user->admin()->entered())
		{
			return;
		}

		Firebird::LocalStatus s;
		Firebird::CheckStatusWrapper statusWrapper(&s);

		Firebird::string userName(user->userName()->get());
		prepareName(userName, '"');

		Firebird::string sql;
		if (user->admin()->get() == 0)
		{
			Firebird::string userName2(user->userName()->get());
			prepareName(userName2, '\'');
			Firebird::string selGrantor;
			selGrantor.printf("SELECT RDB$GRANTOR FROM RDB$USER_PRIVILEGES "
				"WHERE RDB$USER = '******' AND RDB$RELATION_NAME = '%s' AND RDB$PRIVILEGE = 'M'",
				userName2.c_str(), ADMIN_ROLE);
			Message out;
			Field<Varying> grantor(out, MAX_SQL_IDENTIFIER_SIZE);
			Firebird::IResultSet* curs = att->openCursor(&statusWrapper, tra, selGrantor.length(),
				selGrantor.c_str(), SQL_DIALECT_V6, NULL, NULL, out.getMetadata(), NULL, 0);
			check(&statusWrapper);

			bool hasGrant = curs->fetchNext(&statusWrapper, out.getBuffer()) == Firebird::IStatus::RESULT_OK;
			curs->close(&statusWrapper);
			check(&statusWrapper);

			if (hasGrant)
			{
				selGrantor = grantor;
				prepareName(selGrantor, '"');

				sql.printf("REVOKE %s FROM \"%s\" GRANTED BY \"%s\"",
					ADMIN_ROLE, userName.c_str(), selGrantor.c_str());
			}
			else
			{
				if (ignoreRevoke)
					return;

				// no grant - let engine produce correct error message
				sql.printf("REVOKE %s FROM \"%s\"", ADMIN_ROLE, userName.c_str());
			}
		}
		else
		{
			sql.printf("GRANT %s TO \"%s\"", ADMIN_ROLE, userName.c_str());
		}

		att->execute(&statusWrapper, tra, sql.length(), sql.c_str(),
			SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
		check(&statusWrapper);
	}
예제 #3
0
TracePlugin* FB_CARG TraceFactoryImpl::trace_create(Firebird::IStatus* status, TraceInitInfo* initInfo)
{
	Firebird::MasterInterfacePtr master;
	const char* dbname = NULL;
	try
	{
		master->upgradeInterface(initInfo, FB_TRACE_INIT_INFO_VERSION, upInfo);

		dbname = initInfo->getDatabaseName();
		if (!dbname)
			dbname = "";

		TracePluginConfig config;
		TraceCfgReader::readTraceConfiguration(initInfo->getConfigText(), dbname, config);

		TraceDatabaseConnection* connection = initInfo->getConnection();
		if (connection)
			master->upgradeInterface(connection, FB_TRACE_CONNECTION_VERSION, upInfo);

		if (!config.enabled ||
			(config.connection_id && connection &&
				(connection->getConnectionID() != SLONG(config.connection_id))))
		{
			return NULL; // Plugin is not needed, no error happened.
		}

		Firebird::AutoPtr<TraceLogWriter, Firebird::SimpleRelease<TraceLogWriter> >
			logWriter(initInfo->getLogWriter());

		if (logWriter)
			config.log_filename = "";

		return new TracePluginImpl(config, initInfo);	// Everything is ok, we created a plugin

	}
	catch (Firebird::Exception& ex)
	{
		// put error into trace log
		TraceLogWriter* logWriter = initInfo->getLogWriter();
		if (logWriter)
		{
			master->upgradeInterface(logWriter, FB_TRACE_LOG_WRITER_VERSION, upInfo);
			const char* strEx = TracePluginImpl::marshal_exception(ex);
			Firebird::string err;
			if (dbname)
				err.printf("Error creating trace session for database \"%s\":\n%s\n", dbname, strEx);
			else
				err.printf("Error creating trace session for service manager attachment:\n%s\n", strEx);

			logWriter->write(err.c_str(), err.length());
			logWriter->release();
		}
		else
			ex.stuffException(status);
	}

	return NULL;
}
예제 #4
0
파일: ods.cpp 프로젝트: Alexpux/firebird
Firebird::string pagtype(UCHAR type)
{
	// Print pretty name for database page type

	const char* nameArray[pag_max + 1] = {
		"purposely undefined",
		"database header",
		"page inventory",
		"transaction inventory",
		"pointer",
		"data",
		"index root",
		"index B-tree",
		"blob",
		"generators",
		"SCN inventory"
	};

	Firebird::string rc;
	if (type < FB_NELEM(nameArray))
		rc = nameArray[type];
	else
		rc.printf("unknown (%d)", type);

	return rc;
}
예제 #5
0
ModuleLoader::Module* ModuleLoader::loadModule(ISC_STATUS* status, const Firebird::PathName& modPath)
{
	void* module = dlopen(modPath.nullStr(), FB_RTLD_MODE);
	if (module == NULL)
	{
		if (status)
		{
			status[0] = isc_arg_gds;
			status[1] = isc_random;
			status[2] = isc_arg_string;
			status[3] = (ISC_STATUS) dlerror();
			status[4] = isc_arg_end;
		}

		return 0;
	}

#ifdef DEBUG_THREAD_IN_UNLOADED_LIBRARY
	Firebird::string command;
	command.printf("echo +++ %s +++ >>/tmp/fbmaps;date >> /tmp/fbmaps;cat /proc/%d/maps >>/tmp/fbmaps",
		modPath.c_str(), getpid());
	system(command.c_str());
#endif

	return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(*getDefaultMemoryPool(), modPath, module);
}
예제 #6
0
// Lookup and format message.  Return as much of formatted string as fits in caller's buffer.
int fb_msg_format(void* handle, USHORT facility, USHORT number, unsigned int bsize, TEXT* buffer,
	const MsgFormat::SafeArg& arg)
{
	// The field MESSAGES.TEXT is 118 bytes long.
	int total_msg = 0;
	char msg[120] = "";
	const int n = gds__msg_lookup(handle, facility, number, sizeof(msg), msg, NULL);

	if (n > 0 && unsigned(n) < sizeof(msg))
	{
		// Shameful bridge, gds__msg_format emulation for old format messages.
		if (strchr(msg, '%'))
		{
			const TEXT* rep[5];
			arg.dump(rep, 5);
			total_msg = fb_utils::snprintf(buffer, bsize, msg, rep[0], rep[1], rep[2], rep[3], rep[4]);
		}
		else
			total_msg = MsgPrint(buffer, bsize, msg, arg);
	}
	else
	{
		Firebird::string s;
		s.printf("can't format message %d:%d -- ", facility, number);
		if (n == -1)
			s += "message text not found";
		else if (n == -2)
		{
			s += "message file ";
			s += fb_utils::getPrefix(Firebird::DirType::FB_DIR_MSG, MSG_FILE).ToString();
			s += " not found";
		}
		else
		{
			fb_utils::snprintf(buffer, bsize, "message system code %d", n);
			s += buffer;
		}
		total_msg = s.copyTo(buffer, bsize);
	}

	return (n > 0 ? total_msg : -total_msg);
}
예제 #7
0
ModuleLoader::Module* ModuleLoader::loadModule(const Firebird::PathName& modPath)
{
	void* module = dlopen(modPath.nullStr(), FB_RTLD_MODE);
	if (module == NULL)
	{
#ifdef DEV_BUILD
//		gds__log("loadModule failed loading %s: %s", modPath.c_str(), dlerror());
#endif
		return 0;
	}

#ifdef DEBUG_THREAD_IN_UNLOADED_LIBRARY
	Firebird::string command;
	command.printf("echo +++ %s +++ >>/tmp/fbmaps;date >> /tmp/fbmaps;cat /proc/%d/maps >>/tmp/fbmaps",
		modPath.c_str(), getpid());
	system(command.c_str());
#endif

	return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(module);
}
예제 #8
0
// allow different users to read\write\delete files in lock directory
// in case of any error just log it and don't stop engine execution
void adjustLockDirectoryAccess(const char* pathname)
{
	PSECURITY_DESCRIPTOR pSecDesc = NULL;
	PSID pSID_Users = NULL;
	PSID pSID_Administrators = NULL;
	PACL pNewACL = NULL;
	try
	{
		// We should pass root directory in format "C:\" into GetVolumeInformation().
		// In case of pathname is not local folder (i.e. \\share\folder) let
		// GetVolumeInformation() return an error.
		Firebird::PathName root(pathname);
		const Firebird::PathName::size_type pos = root.find(':', 0);
		if (pos == 1)
		{
			root.erase(pos + 1, root.length());
			PathUtils::ensureSeparator(root);
		}

		DWORD fsflags;
		if (!GetVolumeInformation(root.c_str(), NULL, 0, NULL, NULL, &fsflags, NULL, 0))
			Firebird::system_error::raise("GetVolumeInformation");

		if (!(fsflags & FS_PERSISTENT_ACLS))
			return;

		// Adjust security for our new folder : allow BUILTIN\Users group to
		// read\write\delete files
		PACL pOldACL = NULL;

		if (GetNamedSecurityInfo((LPSTR) pathname,
				SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
				NULL, NULL, &pOldACL, NULL,
				&pSecDesc) != ERROR_SUCCESS)
		{
			Firebird::system_error::raise("GetNamedSecurityInfo");
		}

		SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_NT_AUTHORITY;
		if (!AllocateAndInitializeSid(&sidAuth, 2, SECURITY_BUILTIN_DOMAIN_RID,
			DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &pSID_Users))
		{
			Firebird::system_error::raise("AllocateAndInitializeSid");
		}

		if (!AllocateAndInitializeSid(&sidAuth, 2, SECURITY_BUILTIN_DOMAIN_RID,
			DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSID_Administrators))
		{
			Firebird::system_error::raise("AllocateAndInitializeSid");
		}

		EXPLICIT_ACCESS eas[2];
		memset(eas, 0, sizeof(eas));

		eas[0].grfAccessPermissions = FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE;
		eas[0].grfAccessMode = GRANT_ACCESS;
		eas[0].grfInheritance = SUB_OBJECTS_ONLY_INHERIT;
		eas[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
		eas[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
		eas[0].Trustee.ptstrName  = (LPSTR) pSID_Users;

		eas[1].grfAccessPermissions = FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE;
		eas[1].grfAccessMode = GRANT_ACCESS;
		eas[1].grfInheritance = SUB_OBJECTS_ONLY_INHERIT;
		eas[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
		eas[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
		eas[1].Trustee.ptstrName  = (LPSTR) pSID_Administrators;

		if (SetEntriesInAcl(2, eas, pOldACL, &pNewACL) != ERROR_SUCCESS)
			Firebird::system_error::raise("SetEntriesInAcl");

		if (SetNamedSecurityInfo((LPSTR) pathname,
				SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
				NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS)
		{
			Firebird::system_error::raise("SetNamedSecurityInfo");
		}
	}
	catch (const Firebird::Exception& ex)
	{
		Firebird::string str;
		str.printf("Error adjusting access rights for folder \"%s\" :", pathname);

		iscLogException(str.c_str(), ex);
	}

	if (pSID_Users) {
		FreeSid(pSID_Users);
	}
	if (pSID_Administrators) {
		FreeSid(pSID_Administrators);
	}
	if (pNewACL) {
		LocalFree(pNewACL);
	}
	if (pSecDesc) {
		LocalFree(pSecDesc);
	}
}
예제 #9
0
파일: evl.cpp 프로젝트: narolez571/firebird
void EVL_validate(thread_db* tdbb, const Item& item, const ItemInfo* itemInfo, dsc* desc, bool null)
{
/**************************************
 *
 *	E V L _ v a l i d a t e
 *
 **************************************
 *
 * Functional description
 *	Validate argument/variable for not null and check constraint
 *
 **************************************/
	if (itemInfo == NULL)
		return;

	jrd_req* request = tdbb->getRequest();
	bool err = false;

	if (null && !itemInfo->nullable)
		err = true;

	const char* value = NULL_STRING_MARK;
	VaryStr<128> temp;

	MapFieldInfo::ValueType fieldInfo;
	if (!err && itemInfo->fullDomain &&
		request->getStatement()->mapFieldInfo.get(itemInfo->field, fieldInfo) &&
		fieldInfo.validationExpr)
	{
		if (desc && null)
			desc->dsc_flags |= DSC_null;

		const bool desc_is_null = !desc || (desc->dsc_flags & DSC_null);

		request->req_domain_validation = desc;
		const USHORT flags = request->req_flags;

		if (!fieldInfo.validationExpr->execute(tdbb, request) && !(request->req_flags & req_null))
		{
			const USHORT length = desc_is_null ? 0 :
				MOV_make_string(desc, ttype_dynamic, &value, &temp, sizeof(temp) - 1);

			if (desc_is_null)
				value = NULL_STRING_MARK;
			else if (!length)
				value = "";
			else
				const_cast<char*>(value)[length] = 0;	// safe cast - data is on our local stack

			err = true;
		}

		request->req_flags = flags;
	}

	Firebird::string s;

	if (err)
	{
		ISC_STATUS status = isc_not_valid_for_var;
		const char* arg;

		if (item.type == Item::TYPE_CAST)
		{
			status = isc_not_valid_for;
			arg = "CAST";
		}
		else
		{
			if (itemInfo->name.isEmpty())
			{
				int index = item.index + 1;

				status = isc_not_valid_for;

				if (item.type == Item::TYPE_VARIABLE)
				{
					const jrd_prc* procedure = request->getStatement()->procedure;

					if (procedure)
					{
						if (index <= int(procedure->getOutputFields().getCount()))
							s.printf("output parameter number %d", index);
						else
						{
							s.printf("variable number %d",
								index - int(procedure->getOutputFields().getCount()));
						}
					}
					else
						s.printf("variable number %d", index);
				}
				else if (item.type == Item::TYPE_PARAMETER && item.subType == 0)
					s.printf("input parameter number %d", (index - 1) / 2 + 1);
				else if (item.type == Item::TYPE_PARAMETER && item.subType == 1)
					s.printf("output parameter number %d", index);

				if (s.isEmpty())
					arg = UNKNOWN_STRING_MARK;
				else
					arg = s.c_str();
			}
			else
				arg = itemInfo->name.c_str();
		}

		ERR_post(Arg::Gds(status) << Arg::Str(arg) << Arg::Str(value));
	}
}
예제 #10
0
int gsec(Firebird::UtilSvc* uSvc)
{
/**************************************
 *
 *	c o m m o n _ m a i n
 *
 **************************************
 *
 * Functional description
 *	If there is no command line, prompt for one, read it
 *	and make an artificial argv.   Otherwise, pass
 *	the specified argv to SECURITY_exec_line (see below).
 *
 **************************************/
	int exit_code = FINI_OK;
	Firebird::UtilSvc::ArgvType& argv = uSvc->argv;

	TEXT stuff[MAXSTUFF];		// a place to put stuff in interactive mode

	tsec tsecInstance(uSvc);
	tsec* tdsec = &tsecInstance;
	tsec::putSpecific(tdsec);

	StackUserData u;
	tdsec->tsec_user_data = &u;

	const unsigned char* block;
	unsigned int bs = uSvc->getAuthBlock(&block);
	if (bs)
	{
		u.authenticationBlock.add(block, bs);
	}

	try {
	// Perform some special handling when run as a Firebird service.

	tdsec->tsec_throw = true;
	tdsec->tsec_interactive = !uSvc->isService();
	UserData* user_data = tdsec->tsec_user_data;

	//if (!uSvc->isService() && argv.getCount() == 1)
	//	GSEC_error(GsecMsg101); // use gsec -? to get help

	int ret = parse_cmd_line(argv, tdsec);
	if (!uSvc->isService() && ret == -2) // user asked for help
		GSEC_exit();

	Firebird::PathName databaseName;
	const bool databaseNameEntered = user_data->database.entered();
	if (databaseNameEntered)
	{
		databaseName = user_data->database.get();
	}
	else
	{
		const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig());
		databaseName = defConf->getSecurityDatabase();
	}

	const Firebird::string sqlRoleName(user_data->role.entered() ? user_data->role.get() : "");

	Firebird::PathName serverName;
	const bool useServices = !uSvc->isService();

	switch (ISC_extract_host(databaseName, serverName, true))
	{
	case ISC_PROTOCOL_TCPIP:
		serverName += ":";
		break;
	case ISC_PROTOCOL_WLAN:
		serverName = "\\\\" + serverName + "\\";
		break;
	}

	if (!useServices)
	{
		serverName = "";
	}
	Firebird::LocalStatus s;
	user_data->database.set(&s, databaseName.c_str());
	check(&s);

	Firebird::RefPtr<IManagement> manager;
	ISC_STATUS_ARRAY status;

	if (!useServices)
	{
		// Get remote address info for management plugin
		Firebird::string network_protocol, remote_address;
		Firebird::ClumpletWriter tmp(Firebird::ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
		uSvc->fillDpb(tmp);

		if (tmp.find(isc_dpb_address_path))
		{
			Firebird::ClumpletReader address_stack(Firebird::ClumpletReader::UnTagged,
												   tmp.getBytes(), tmp.getClumpLength());

			while (!address_stack.isEof())
			{
				if (address_stack.getClumpTag() != isc_dpb_address)
				{
					address_stack.moveNext();
					continue;
				}

				Firebird::ClumpletReader address(Firebird::ClumpletReader::UnTagged,
												 address_stack.getBytes(), address_stack.getClumpLength());

				while (!address.isEof())
				{
					switch (address.getClumpTag())
					{
						case isc_dpb_addr_protocol:
							address.getString(network_protocol);
							break;
						case isc_dpb_addr_endpoint:
							address.getString(remote_address);
							break;
						default:
							break;
					}

					address.moveNext();
				}

				break;
			}
		}

		// Create config to pass -DATABASE parameter value to plugin
		Firebird::string databaseText;
		databaseText.printf("SecurityDatabase = %s\n", databaseName.c_str());
		ConfigFile gsecDatabase(ConfigFile::USE_TEXT, databaseText.c_str());
		Firebird::RefPtr<Config> defaultConfig(Config::getDefaultConfig());
		Firebird::RefPtr<Config> pseudoConfig(new Config(gsecDatabase, *defaultConfig));

		uSvc->checkService();

		fb_assert(user_data->dba.entered() || user_data->authenticationBlock.hasData());
		if (user_data->dba.entered() || user_data->authenticationBlock.hasData())
		{
			class GsecInfo : public Firebird::AutoIface<ILogonInfo, FB_AUTH_LOGON_INFO_VERSION>
			{
			public:
				GsecInfo(const char* pDba, const char* pRole,
						 const char* pProtocol, const char* pAddress,
						 const UserData::AuthenticationBlock* pAuthBlock)
					: dba(pDba), sqlRole(pRole),
					  protocol(pProtocol), address(pAddress),
					  authBytes(pAuthBlock->getCount() ? pAuthBlock->begin() : NULL),
					  authLength(pAuthBlock->getCount())
				{ }

				// ILogonInfo implementation
				const char* FB_CARG name()
				{
					return dba;
				}

				const char* FB_CARG role()
				{
					return sqlRole;
				}

				const char* FB_CARG networkProtocol()
				{
					return protocol;
				}

				const char* FB_CARG remoteAddress()
				{
					return address;
				}

				const unsigned char* FB_CARG authBlock(unsigned* length)
				{
					*length = authLength;
					return authBytes;
				}

			private:
				const char* dba;
				const char* sqlRole;
				const char* protocol;
				const char* address;
				const unsigned char* authBytes;
				unsigned int authLength;
			};
예제 #11
0
static void setAttr(Firebird::string& attr, IIntUserField* field)
{
	attr.printf("%d", field->get());
}
예제 #12
0
int CLIB_ROUTINE main( int argc, char **argv)
{
/**************************************
 *
 *	m a i n
 *
 **************************************
 *
 * Functional description
 *	Install or remove a Firebird service.
 *
 **************************************/
	USHORT sw_command = COMMAND_NONE;
	bool sw_version = false;
	USHORT sw_startup = STARTUP_AUTO;
	USHORT sw_mode = DEFAULT_PRIORITY;
	USHORT sw_guardian = NO_GUARDIAN;
	USHORT sw_arch = ARCH_SS;
	bool sw_interactive = false;

	const TEXT* instance = FB_DEFAULT_INSTANCE;

	const TEXT* username = NULL;
	const TEXT* password = NULL;

	// Let's get the root directory from the instance path of this program.
	// argv[0] is only _mostly_ guaranteed to give this info,
	// so we GetModuleFileName()
	TEXT directory[MAXPATHLEN];
	const USHORT len = GetModuleFileName(NULL, directory, sizeof(directory));
	if (len == 0)
		return svc_error(GetLastError(), "GetModuleFileName", NULL);

	fb_assert(len <= sizeof(directory));

	// Get to the last '\' (this one precedes the filename part). There is
	// always one after a call to GetModuleFileName().
	TEXT* p = directory + len;

	while (p != directory)
	{
		--p;

		if ((*p) == '\\')
			break;
	}
	*p = '\0';

	TEXT full_username[128];
	TEXT oem_username[128];
	TEXT keyb_password[64];

	const TEXT* const* const end = argv + argc;
	while (++argv < end)
	{
		if (**argv != '-')
		{
			int i;
			const TEXT* cmd;
			for (i = 0; cmd = commands[i].name; i++)
			{
				const TEXT* q;
				for (p = *argv, q = cmd; *p && UPPER(*p) == *q; p++, q++)
					;
				if (!*p && commands[i].abbrev <= (USHORT) (q - cmd))
					break;
			}
			if (!cmd)
			{
				printf("Unknown command \"%s\"\n", *argv);
				usage_exit();
			}
			sw_command = commands[i].code;
		}
		else
		{
			p = *argv + 1;
			switch (UPPER(*p))
			{
				case 'A':
					sw_startup = STARTUP_AUTO;
					break;

				case 'D':
					sw_startup = STARTUP_DEMAND;
					break;

				/*
				case 'R':
					sw_mode = NORMAL_PRIORITY;
					break;
				*/
				case 'B':
					sw_mode = HIGH_PRIORITY;
					break;

				case 'Z':
					sw_version = true;
					break;

				case 'G':
					sw_guardian = USE_GUARDIAN;
					break;

				case 'L':
					if (++argv < end)
						username = *argv;
					if (++argv < end)
					{
						if (**argv == '-')	// Next switch
							--argv;
						else
							password = *argv;
					}
					break;

				case 'I':
					sw_interactive = true;
					break;

				case 'N':
					if (++argv < end)
						instance = *argv;
					break;

				case '?':
					usage_exit();

				default:
					printf("Unknown switch \"%s\"\n", p);
					usage_exit();
			}
		}
	}

	if (sw_version)
		printf("instsvc version %s\n", FB_VERSION);

	if (sw_command == COMMAND_NONE || (username && sw_command != COMMAND_INSTALL))
	{
		usage_exit();
	}

	if (sw_command == COMMAND_INSTALL && username != 0)
	{
		if (sw_interactive)
		{
			printf("\"Interact with desktop\" mode can be set for LocalSystem account only");
			exit(FINI_ERROR);
		}

		const char* limit = username;
		while (*limit != '\0' && *limit != '\\')
			++limit;

		if (!*limit)
		{
			DWORD cnlen = sizeof(full_username) - 1;
			GetComputerName(full_username, &cnlen);
			strcat(full_username, "\\");
			strncat(full_username, username, sizeof(full_username) - (cnlen + 1));
		}
		else
		{
			strncpy(full_username, username, sizeof(full_username));
		}

		full_username[sizeof(full_username) - 1] = '\0';

		CharToOem(full_username, oem_username);

		username = full_username;

		if (password == 0)
		{
			printf("Enter %s user password : "******"\n");
			OemToChar(keyb_password, keyb_password);
			password = keyb_password;
		}

		// Let's grant "Logon as a Service" right to the -login user
		switch (SERVICES_grant_privilege(full_username, svc_error, L"SeServiceLogonRight"))
		{
			case FB_PRIVILEGE_ALREADY_GRANTED:
				/*
				// OM - I think it is better not to bother the admin with this message.
				printf("The 'Logon as a Service' right was already granted to %s\n", oem_username);
				*/
				break;
			case FB_SUCCESS:
				printf("The 'Logon as a Service' right has been granted to %s\n", oem_username);
				break;
			case FB_FAILURE:
			default:
				printf("Failed granting the 'Logon as a Service' right to %s\n", oem_username);
				exit(FINI_ERROR);
				break;
		}

		// Let's grant "Adjust memory quotas for a process" right to the -login user
		switch (SERVICES_grant_privilege(full_username, svc_error, L"SeIncreaseQuotaPrivilege"))
		{
			case FB_PRIVILEGE_ALREADY_GRANTED:
				break;
			case FB_SUCCESS:
				printf("The 'Adjust memory quotas for a process' right has been granted to %s\n", oem_username);
				break;
			case FB_FAILURE:
			default:
				printf("Failed granting the 'Adjust memory quotas for a process' right to %s\n", oem_username);
				exit(FINI_ERROR);
				break;
		}
	}

	DWORD dwScmManagerAccess = SC_MANAGER_ALL_ACCESS;

	switch (sw_command)
	{
		case COMMAND_INSTALL:
		case COMMAND_REMOVE:
			dwScmManagerAccess = SC_MANAGER_CREATE_SERVICE;
			break;

		case COMMAND_START:
		case COMMAND_STOP:
			dwScmManagerAccess = SC_MANAGER_CONNECT;
			break;

		case COMMAND_QUERY:
			dwScmManagerAccess = SC_MANAGER_ENUMERATE_SERVICE;
			break;
    }

	const SC_HANDLE manager = OpenSCManager(NULL, NULL, dwScmManagerAccess);
	if (manager == NULL)
	{
		svc_error(GetLastError(), "OpenSCManager", NULL);
		exit(FINI_ERROR);
	}

	USHORT status, status2;
	SC_HANDLE service;

	Firebird::string guard_service_name, guard_display_name;
	guard_service_name.printf(ISCGUARD_SERVICE, instance);
	guard_display_name.printf(ISCGUARD_DISPLAY_NAME, instance);

	Firebird::string remote_service_name, remote_display_name;
	remote_service_name.printf(REMOTE_SERVICE, instance);
	remote_display_name.printf(REMOTE_DISPLAY_NAME, instance);

	Firebird::string switches;
	if (strchr(instance, ' '))
		switches.printf("-s \"%s\"", instance);
	else
		switches.printf("-s %s", instance);

	switch (sw_command)
	{
		case COMMAND_INSTALL:
			// First, lets do the guardian, if it has been specified
			if (sw_guardian)
			{
				status = SERVICES_install(manager,
										  guard_service_name.c_str(),
										  guard_display_name.c_str(),
										  ISCGUARD_DISPLAY_DESCR,
										  ISCGUARD_EXECUTABLE,
										  directory,
										  switches.c_str(),
										  NULL,
										  sw_startup,
										  username,
										  password,
										  false, // interactive_mode
										  true, // auto_restart
										  svc_error);

				status2 = FB_SUCCESS;

				if (username != 0)
				{
					status2 =
						SERVICES_grant_access_rights(guard_service_name.c_str(), username, svc_error);
				}

				if (status == FB_SUCCESS && status2 == FB_SUCCESS)
				{
					printf("Service \"%s\" successfully created.\n", guard_display_name.c_str());
				}

				// Set sw_startup to manual in preparation for install the service
				sw_startup = STARTUP_DEMAND;
			}

			// do the install of the server
			status = SERVICES_install(manager,
									  remote_service_name.c_str(),
									  remote_display_name.c_str(),
									  REMOTE_DISPLAY_DESCR,
									  REMOTE_EXECUTABLE,
									  directory,
									  switches.c_str(),
									  NULL,
									  sw_startup,
									  username,
									  password,
									  sw_interactive,
									  !sw_guardian,
									  svc_error);

			status2 = FB_SUCCESS;

			if (username != 0)
			{
				status2 =
					SERVICES_grant_access_rights(remote_service_name.c_str(), username, svc_error);
			}

			if (status == FB_SUCCESS && status2 == FB_SUCCESS)
			{
				printf("Service \"%s\" successfully created.\n", remote_display_name.c_str());
			}

			break;

		case COMMAND_REMOVE:
			service = OpenService(manager, guard_service_name.c_str(), SERVICE_ALL_ACCESS);
			if (service)
			{
				CloseServiceHandle(service);

				status = SERVICES_remove(manager, guard_service_name.c_str(),
										 /*guard_display_name.c_str(),*/ svc_error);

				if (status == FB_SUCCESS)
				{
					printf("Service \"%s\" successfully deleted.\n", guard_display_name.c_str());
				}
				else if (status == IB_SERVICE_RUNNING)
				{
					printf("Service \"%s\" not deleted.\n", guard_display_name.c_str());
					printf("You must stop it before attempting to delete it.\n\n");
				}
			}
			else
			{
				status = (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) ? FB_SUCCESS : FB_FAILURE;
			}

			service = OpenService(manager, remote_service_name.c_str(), SERVICE_ALL_ACCESS);
			if (service)
			{
				CloseServiceHandle(service);

				status2 = SERVICES_remove(manager, remote_service_name.c_str(),
										  /*remote_display_name.c_str(),*/ svc_error);

				if (status2 == FB_SUCCESS)
				{
					printf("Service \"%s\" successfully deleted.\n", remote_display_name.c_str());
				}
				else if (status2 == IB_SERVICE_RUNNING)
				{
					printf("Service \"%s\" not deleted.\n", remote_display_name.c_str());
					printf("You must stop it before attempting to delete it.\n\n");
				}
			}
			else
			{
				status2 = (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) ? FB_SUCCESS : FB_FAILURE;
			}

			if (status != FB_SUCCESS && status2 != FB_SUCCESS)
				status = FB_FAILURE;

			break;

		case COMMAND_START:
			// Test for use of the guardian. If so, start the guardian else start the server
			service = OpenService(manager, guard_service_name.c_str(), SERVICE_START);
			if (service)
			{
				CloseServiceHandle(service);

				status = SERVICES_start(manager, guard_service_name.c_str(),
										/*guard_display_name.c_str(),*/ sw_mode, svc_error);

				if (status == FB_SUCCESS)
				{
					printf("Service \"%s\" successfully started.\n", guard_display_name.c_str());
				}
			}
			else
			{
				CloseServiceHandle(service);

				status = SERVICES_start(manager, remote_service_name.c_str(),
										/*remote_display_name.c_str(),*/ sw_mode, svc_error);

				if (status == FB_SUCCESS)
				{
					printf("Service \"%s\" successfully started.\n", remote_display_name.c_str());
				}
			}
			break;

		case COMMAND_STOP:
			// Test for use of the guardian. If so, stop the guardian else stop the server
			service = OpenService(manager, guard_service_name.c_str(), SERVICE_STOP);
			if (service)
			{
				CloseServiceHandle(service);

				status = SERVICES_stop(manager, guard_service_name.c_str(),
									   /*guard_display_name.c_str(),*/ svc_error);

				if (status == FB_SUCCESS)
				{
					printf("Service \"%s\" successfully stopped.\n", guard_display_name.c_str());
				}
			}
			else
			{
				CloseServiceHandle(service);

				status = SERVICES_stop(manager, remote_service_name.c_str(),
									   /*remote_display_name.c_str(),*/ svc_error);

				if (status == FB_SUCCESS)
				{
					printf("Service \"%s\" successfully stopped.\n", remote_display_name.c_str());
				}
			}
			break;

		case COMMAND_QUERY:
			if (svc_query_ex(manager) == FB_FAILURE)
			{
				svc_query(guard_service_name.c_str(), guard_display_name.c_str(), manager);
				svc_query(remote_service_name.c_str(), remote_display_name.c_str(), manager);
			}

			status = FB_SUCCESS;
			break;

		default:
			status = FB_SUCCESS;
	}

	CloseServiceHandle(manager);

	return (status == FB_SUCCESS) ? FINI_OK : FINI_ERROR;
}