You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

493 lines
13 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software is provided to you as Sample Source Code as defined in the accompanying
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
* section 1.L.
*
* This software and the related documents are provided as is, with no express or implied
* warranties, other than those that are expressly stated in the License.
*/
#define UNICODE
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#include <Windows.h>
#include <Winsvc.h>
#include <string>
#include <iostream>
#include <fstream>
using std::string;
using std::endl;
using std::cout;
using std::wstring;
using std::cerr;
using std::ofstream;
static wchar_t * ServiceNameW = L"PinLauncherService";
static wchar_t * ServiceDisplayNameW = L"Pin Launcher Service";
static wchar_t * BinaryNameW = L"w_pin_service_launcher.exe";
// perform administrative actions, this class is used
// when the process runs as regular process (not as service)
class SERVICE_ADMIN
{
public:
static void Main(int argc, wchar_t * argv[]);
private:
BOOL Create();
BOOL Delete();
BOOL Start(DWORD argc, LPCTSTR * argv);
BOOL Stop();
void Usage();
};
// functions to be used when the process runs as service
class SERVICE_MANAGER
{
public:
static void WINAPI Main(DWORD argc, LPTSTR * argv);
static void WINAPI ControlHandler(DWORD opcode);
static void CreatePinProcessAndWait(DWORD argc, LPCWSTR * argv);
static void StopService(); //never returns
static void OpenFile();
private:
static void LaunchProcess(wstring cmdLine);
static SERVICE_STATUS status;
static SERVICE_STATUS_HANDLE statusHandle;
static ofstream outFile;
};
SERVICE_STATUS SERVICE_MANAGER::status;
SERVICE_STATUS_HANDLE SERVICE_MANAGER::statusHandle;
ofstream SERVICE_MANAGER::outFile;
// main function
int wmain(int argc, wchar_t * argv[])
{
if((argc >= 2) && ((wcscmp(argv[1], L"-admin") == 0) || (wcscmp(argv[1], L"-help") == 0)))
{
SERVICE_ADMIN::Main(argc, argv);
}
else
{
SERVICE_MANAGER::OpenFile();
SERVICE_TABLE_ENTRY dispatchData[]={{ServiceNameW, SERVICE_MANAGER::Main},{NULL, NULL}};
StartServiceCtrlDispatcher(dispatchData);
}
return 0;
}
//manager impl
void SERVICE_MANAGER::CreatePinProcessAndWait(DWORD argc, LPCWSTR * argv)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
si.cb = sizeof(STARTUPINFO);
memset(&pi, 0, sizeof(pi));
wstring cmdLine = L"";
for(DWORD i = 0; i < argc; i++)
{
cmdLine += wstring(L"\"") + argv[i] + L"\"";
if(i < argc -1)
{
cmdLine += L" ";
}
}
if (!CreateProcess(NULL, (LPWSTR)cmdLine.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
outFile << "Failed to CreateProcess, " << GetLastError() << endl;
}
if(WaitForSingleObject( pi.hProcess, 60*1000 ) != WAIT_OBJECT_0)
{
outFile << "Pin didn't finish running after 60 sec. " << endl;
}
return;
}
void WINAPI SERVICE_MANAGER::Main(DWORD argc, LPTSTR *argv)
{
status.dwServiceType = SERVICE_WIN32;
status.dwCurrentState = SERVICE_START_PENDING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
status.dwWin32ExitCode = 0;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
statusHandle = RegisterServiceCtrlHandler(ServiceNameW, SERVICE_MANAGER::ControlHandler);
if (statusHandle == (SERVICE_STATUS_HANDLE)NULL)
{
outFile << "Failed to RegisterServiceCtrlHandler, " << GetLastError() << endl;
return;
}
status.dwCurrentState = SERVICE_RUNNING;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
if (!SetServiceStatus (statusHandle, &status))
{
outFile << "Failed to SetServiceStatus, " << GetLastError() << endl;
return;
}
CreatePinProcessAndWait(argc - 1, (LPCWSTR *)&argv[1]);
StopService();
return;
}
void WINAPI SERVICE_MANAGER::ControlHandler(DWORD opcode)
{
switch(opcode)
{
case SERVICE_CONTROL_PAUSE:
status.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
status.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
status.dwWin32ExitCode = 0;
status.dwCurrentState = SERVICE_STOPPED;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
outFile.flush();
outFile.close();
SetServiceStatus (statusHandle,&status);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
}
return;
}
void SERVICE_MANAGER::StopService()
{
wchar_t binPathArr[2048];
GetModuleFileName(NULL, binPathArr, 2048);
LPCTSTR binPath = binPathArr;
wstring cmdLine = wstring(L"\"") + binPath + L"\"";
cmdLine += L" -admin -stop";
LaunchProcess(cmdLine);
}
void SERVICE_MANAGER::LaunchProcess(wstring cmdLine)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
si.cb = sizeof(STARTUPINFO);
memset(&pi, 0, sizeof(pi));
if (!CreateProcess(NULL, (LPWSTR)cmdLine.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
outFile << "Failed to CreateProcess, " << GetLastError() << endl;
}
return;
}
void SERVICE_MANAGER::OpenFile()
{
wchar_t binPathArr[2048];
GetModuleFileName(NULL, binPathArr, 2048);
size_t serviceExeNameLen = wcslen(BinaryNameW);
size_t servicePathNameLen = wcslen(binPathArr) - serviceExeNameLen;
binPathArr[servicePathNameLen] = L'\0';
SetCurrentDirectory(binPathArr);
wstring fileName = binPathArr;
fileName += BinaryNameW;
fileName += L".service.log";
outFile.open(fileName.c_str());
}
//admin impl
void SERVICE_ADMIN::Main(int argc, wchar_t * argv[])
{
SERVICE_ADMIN admin;
if((argc == 1) ||
((argc == 2) && ((wcscmp(argv[1], L"-admin") == 0) || (wcscmp(argv[1], L"-help") == 0))))
{
return admin.Usage();
}
if(wcscmp(argv[2], L"-create") == 0)
{
if(admin.Create())
{
cerr << "Created service sucessfully!" << endl;
}
else
{
cerr << "Failed to Create service" << endl;
}
}
else if (wcscmp(argv[2], L"-start") == 0)
{
if(admin.Start((DWORD)(argc - 3), (LPCWSTR *)&argv[3]))
{
cerr << "Started service sucessfully!" << endl;
}
else
{
cerr << "Failed to start service" << endl;
}
}
else if (wcscmp(argv[2],L"-stop") == 0)
{
if(admin.Stop())
{
cerr << "Stopped service sucessfully!" << endl;
}
else
{
cerr << "Failed to stop service" << endl;
}
}
else if (wcscmp(argv[2],L"-delete") == 0)
{
if(admin.Delete())
{
cerr << "Deleted service sucessfully!" << endl;
}
else
{
cerr << "Failed to delete service" << endl;
}
}
else
{
admin.Usage();
}
return;
}
BOOL SERVICE_ADMIN::Create()
{
SC_HANDLE manager;
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (manager == NULL)
{
cerr << "Failed to OpenSCManager, " << GetLastError() << endl;
return false;
}
wchar_t binPathArr[2048];
GetModuleFileName(NULL, binPathArr, 2048);
wstring path = binPathArr;
path = L"\"" + path + L"\"";
#if 0 // This code is intended for symbolic link substitution
size_t slashLocation = path.find(L"\\");
wstring drive = path.substr(0, slashLocation);
path = path.substr(slashLocation);
wchar_t targetPath[2048];
QueryDosDevice(drive.c_str(), targetPath, 2048);
path = wstring(targetPath) + path;
if(path.find(L"\\??\\") == 0)
{
/* Remove \??\ */
path = path.substr(4);
}
else if(path.find(L"\\DosDevices\\") == 0)
{
/* Remove \DosDevices\ */
path = path.substr(12);
}
#endif
LPCTSTR binPath = path.c_str();
SC_HANDLE service;
service = CreateService(manager,
ServiceNameW,
ServiceDisplayNameW,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
binPath,
NULL,
NULL,
NULL,
NULL, // log on as Local System
NULL); // no password
if (service == NULL && (GetLastError() != ERROR_SERVICE_EXISTS))
{
cerr << "Failed to CreateService, " << GetLastError() << endl;
CloseServiceHandle(manager);
return false;
}
CloseServiceHandle(manager);
CloseServiceHandle(service);
return true;
}
BOOL SERVICE_ADMIN::Start(DWORD argc, LPCWSTR * argv)
{
SC_HANDLE manager;
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (manager == NULL)
{
cerr << "Failed to OpenSCManager, " << GetLastError() << endl;
return false;
}
SC_HANDLE service;
service = OpenService(manager, ServiceNameW, SERVICE_ALL_ACCESS);
if (service == NULL)
{
cerr << "Failed to OpenService, " << GetLastError() << endl;
CloseServiceHandle(manager);
return false;
}
if(!StartService(service, argc, argv))
{
cerr << "Failed to StartService, " << GetLastError() << endl;
CloseServiceHandle(manager);
CloseServiceHandle(service);
return false;
}
Sleep(12000);
//maximum 8k
SERVICE_STATUS_PROCESS * pServiceStatusProcess = (SERVICE_STATUS_PROCESS *)malloc(0x2000);
pServiceStatusProcess->dwCurrentState = SERVICE_START_PENDING;
//let pin to do it's job, it has 60 seconds to complete
int timer = 12;
while((timer != 0) && (pServiceStatusProcess->dwCurrentState != SERVICE_STOPPED))
{
timer--;
DWORD bytesNeeded = 0;
if(!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)pServiceStatusProcess, 0x2000, &bytesNeeded))
{
cout << "Failed to QueryServiceStatusEx, " << GetLastError() << endl;
CloseServiceHandle(manager);
CloseServiceHandle(service);
free(pServiceStatusProcess);
return false;
}
Sleep(5000);
}
if(pServiceStatusProcess->dwCurrentState != SERVICE_STOPPED)
{
cerr << "Service haven't stopped after 60 seconds" << endl;
CloseServiceHandle(manager);
CloseServiceHandle(service);
free(pServiceStatusProcess);
return false;
}
CloseServiceHandle(manager);
CloseServiceHandle(service);
free(pServiceStatusProcess);
return true;
}
BOOL SERVICE_ADMIN::Stop()
{
SC_HANDLE manager;
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (manager == NULL)
{
cout << "Failed to OpenSCManager, " << GetLastError() << endl;
return false;
}
SC_HANDLE service;
service = OpenService(manager, ServiceNameW, SERVICE_ALL_ACCESS);
if (service == NULL)
{
cout << "Failed to OpenService, " << GetLastError() << endl;
CloseServiceHandle(manager);
return false;
}
SERVICE_STATUS status;
BOOL res = ControlService(service, SERVICE_CONTROL_STOP, &status);
if(!res && (GetLastError() != ERROR_SERVICE_NOT_ACTIVE))
{
cout << "Failed to ControlService, " << GetLastError() << endl;
CloseServiceHandle(manager);
CloseServiceHandle(service);
return false;
}
CloseServiceHandle(manager);
CloseServiceHandle(service);
return true;
}
BOOL SERVICE_ADMIN::Delete()
{
SC_HANDLE manager;
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (manager == NULL)
{
cout << "Failed to OpenSCManager, " << GetLastError() << endl;
return false;
}
SC_HANDLE service;
service = OpenService(manager, ServiceNameW, SERVICE_ALL_ACCESS);
if (service == NULL)
{
cout << "Failed to OpenService, " << GetLastError() << endl;
CloseServiceHandle(manager);
return false;
}
if(!DeleteService(service))
{
cout << "Failed to DeleteService, " << GetLastError() << endl;
CloseServiceHandle(manager);
CloseServiceHandle(service);
return false;
}
CloseServiceHandle(manager);
CloseServiceHandle(service);
return true;
}
void SERVICE_ADMIN::Usage()
{
cerr << "Usage:" << endl;
cerr << "To create the service: -admin -create" << endl;
cerr << "To start the service: -admin -start <pin> <pin arguments>" << endl;
cerr << "To start the service: -admin -stop" << endl;
cerr << "To delete the service: -admin -delete" << endl;
}