250 lines
7.7 KiB
C++
250 lines
7.7 KiB
C++
#pragma region Includes
|
|
#include "SSAservice.h"
|
|
#include "ThreadPool.h"
|
|
#include "PathName.h"
|
|
|
|
#include <string>
|
|
#include <psapi.h>
|
|
#pragma comment(lib, "Psapi.lib")
|
|
|
|
#pragma endregion
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// CSSAservice
|
|
///////////////////////////////////////////////////////////
|
|
|
|
BOOL CSSAservice::FindAgent(HANDLE& hFound, DWORD& pid) const
|
|
{
|
|
DWORD* aProcesses = NULL;
|
|
DWORD nItems = 0, nFound = 0, i = 0;
|
|
|
|
hFound = 0;
|
|
pid = 0;
|
|
|
|
for (nItems = 256; ; nItems *= 2)
|
|
{
|
|
DWORD cbNeeded = 0;
|
|
free(aProcesses);
|
|
aProcesses = (DWORD*)calloc(nItems, sizeof(DWORD));
|
|
if (!EnumProcesses(aProcesses, nItems*sizeof(DWORD), &cbNeeded))
|
|
{
|
|
free(aProcesses);
|
|
return FALSE;
|
|
}
|
|
nFound = cbNeeded / sizeof(DWORD);
|
|
if (nFound < nItems)
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < nFound && hFound == NULL; i++) if (aProcesses[i])
|
|
{
|
|
HANDLE hProcess = ::OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i] );
|
|
if (hProcess != NULL)
|
|
{
|
|
HMODULE hMod;
|
|
DWORD cbNeeded;
|
|
if (::EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) )
|
|
{
|
|
TCHAR szProcessName[MAX_PATH] = { 0 };
|
|
::GetModuleBaseName( hProcess, hMod, szProcessName, sizeof(szProcessName)/sizeof(TCHAR) );
|
|
if (wcsstr(szProcessName, _agent) != NULL)
|
|
{
|
|
hFound = ::OpenProcess( SYNCHRONIZE, FALSE, aProcesses[i] ); // Waitable process handle
|
|
pid = aProcesses[i];
|
|
}
|
|
}
|
|
// Release the handle to the process.
|
|
CloseHandle( hProcess );
|
|
}
|
|
}
|
|
|
|
free(aProcesses);
|
|
return hFound != NULL;
|
|
}
|
|
|
|
BOOL CSSAservice::FindOrCreateAgent(HANDLE& hProcess, DWORD& pid) const
|
|
{
|
|
if (!FindAgent(hProcess, pid))
|
|
{
|
|
STARTUPINFO si = { 0 };
|
|
PROCESS_INFORMATION pi = { 0 };
|
|
si.cb = sizeof(si); // si.wShowWindow = SW_HIDE;
|
|
|
|
std::wstring str;
|
|
str = L"Creating instance of "; str += _agent;
|
|
WriteEventLogEntry(str.c_str());
|
|
if (CreateProcess(_agent,
|
|
NULL, // lpCommandLine
|
|
NULL, // lpProcessAttributes
|
|
NULL, // lpThreadAttributes
|
|
FALSE, // no Handle inheritance
|
|
CREATE_NO_WINDOW | IDLE_PRIORITY_CLASS, // creation flags
|
|
NULL, // Use parent's environment block
|
|
NULL, // Use parent's starting directory
|
|
&si,
|
|
&pi))
|
|
{
|
|
hProcess = pi.hProcess;
|
|
pid = pi.dwProcessId;
|
|
}
|
|
else
|
|
WriteErrorLogEntry(TEXT("CreateProcess"));
|
|
}
|
|
else
|
|
{
|
|
std::wstring str;
|
|
str = L"Attaching to instance of "; str += _agent;
|
|
WriteEventLogEntry(str.c_str());
|
|
}
|
|
return hProcess != 0;
|
|
}
|
|
|
|
void CSSAservice::CheckDirectory() const
|
|
{
|
|
char full[_MAX_PATH] = {0}; ::GetModuleFileNameA(NULL, full, sizeof(full));
|
|
CPathName pn = full;
|
|
::SetCurrentDirectoryA(pn.Path());
|
|
}
|
|
|
|
CSSAservice::CSSAservice(LPCTSTR pszServiceName,
|
|
BOOL fCanStop, BOOL fCanShutdown, BOOL fCanPauseContinue)
|
|
: CServiceBase(pszServiceName, fCanStop, fCanShutdown, fCanPauseContinue), _agent(NULL)
|
|
{
|
|
m_fStopping = FALSE;
|
|
|
|
// Create a manual-reset event that is not signaled at first to indicate
|
|
// the stopped signal of the service.
|
|
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (m_hStoppedEvent == NULL)
|
|
throw GetLastError();
|
|
}
|
|
|
|
|
|
CSSAservice::~CSSAservice(void)
|
|
{
|
|
if (m_hStoppedEvent)
|
|
{
|
|
CloseHandle(m_hStoppedEvent);
|
|
m_hStoppedEvent = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: CSSAservice::OnStart(DWORD, LPWSTR *)
|
|
//
|
|
// PURPOSE: The function is executed when a Start command is sent to the
|
|
// service by the SCM or when the operating system starts (for a service
|
|
// that starts automatically). It specifies actions to take when the
|
|
// service starts. In this code sample, OnStart logs a service-start
|
|
// message to the Application log, and queues the main service function for
|
|
// execution in a thread pool worker thread.
|
|
//
|
|
// PARAMETERS:
|
|
// * dwArgc - number of command line arguments
|
|
// * lpszArgv - array of command line arguments
|
|
//
|
|
// NOTE: A service application is designed to be long running. Therefore,
|
|
// it usually polls or monitors something in the system. The monitoring is
|
|
// set up in the OnStart method. However, OnStart does not actually do the
|
|
// monitoring. The OnStart method must return to the operating system after
|
|
// the service's operation has begun. It must not loop forever or block. To
|
|
// set up a simple monitoring mechanism, one general solution is to create
|
|
// a timer in OnStart. The timer would then raise events in your code
|
|
// periodically, at which time your service could do its monitoring. The
|
|
// other solution is to spawn a new thread to perform the main service
|
|
// functions, which is demonstrated in this code sample.
|
|
//
|
|
void CSSAservice::OnStart(DWORD dwArgc, LPWSTR *lpszArgv)
|
|
{
|
|
// Log a service start message to the Application log.
|
|
WriteEventLogEntry(TEXT("SSAservice Starting"));
|
|
|
|
// Queue the main service function for execution in a worker thread.
|
|
CThreadPool::QueueUserWorkItem(&CSSAservice::ServiceLoop, this);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: CSSAservice::ServiceLoop(void)
|
|
//
|
|
// PURPOSE: The method performs the main function of the service. It runs
|
|
// on a thread pool worker thread.
|
|
//
|
|
void CSSAservice::ServiceLoop(void)
|
|
{
|
|
const int nSeconds = 5;
|
|
CheckDirectory();
|
|
|
|
WIN32_FIND_DATA fd = { 0 };
|
|
HANDLE hf = ::FindFirstFile(TEXT("*.ssa"), &fd);
|
|
if (hf)
|
|
{
|
|
_agent = TEXT("SSAagent.exe");
|
|
::FindClose(hf);
|
|
}
|
|
else
|
|
_agent = TEXT("Authoriz.exe");
|
|
|
|
|
|
HANDLE hProcess = 0;
|
|
DWORD pid = 0;
|
|
FindOrCreateAgent(hProcess, pid);
|
|
|
|
// Periodically check if the service is stopping.
|
|
while (hProcess && !m_fStopping)
|
|
{
|
|
DWORD ret = ::WaitForSingleObject(hProcess, nSeconds * 1000);
|
|
if (ret != WAIT_TIMEOUT)
|
|
{
|
|
WriteEventLogEntry(TEXT("Unexpected agent termination"), EVENTLOG_WARNING_TYPE);
|
|
::CloseHandle(hProcess);
|
|
FindOrCreateAgent(hProcess, pid);
|
|
}
|
|
}
|
|
|
|
if (hProcess)
|
|
{
|
|
::CloseHandle(hProcess);
|
|
HANDLE hAgent = ::OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
|
if (hAgent)
|
|
{
|
|
if (::TerminateProcess(hAgent, 0))
|
|
_agent = NULL;
|
|
else
|
|
WriteErrorLogEntry(TEXT("TerminateProcess"));
|
|
::CloseHandle(hAgent);
|
|
}
|
|
else
|
|
WriteErrorLogEntry(TEXT("OpenProcess(PROCESS_TERMINATE)"));
|
|
}
|
|
|
|
// Signal the stopped event.
|
|
SetEvent(m_hStoppedEvent);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: CSSAservice::OnStop(void)
|
|
//
|
|
// PURPOSE: The function is executed when a Stop command is sent to the
|
|
// service by SCM. It specifies actions to take when a service stops
|
|
// running. In this code sample, OnStop logs a service-stop message to the
|
|
// Application log, and waits for the finish of the main service function.
|
|
//
|
|
// COMMENTS:
|
|
// Be sure to periodically call ReportServiceStatus() with
|
|
// SERVICE_STOP_PENDING if the procedure is going to take long time.
|
|
//
|
|
void CSSAservice::OnStop()
|
|
{
|
|
// Log a service stop message to the Application log.
|
|
WriteEventLogEntry(L"SSAservice Stopping");
|
|
|
|
// Indicate that the service is stopping and wait for the finish of the
|
|
// main service function (ServiceWorkerThread).
|
|
m_fStopping = TRUE;
|
|
if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
|
|
throw GetLastError();
|
|
}
|