mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
62e8b90130
sql/nt_servc.cc: Typo fix (duplicate fuctions body)
570 lines
16 KiB
C++
570 lines
16 KiB
C++
/* ------------------------------------------------------------------------
|
|
Windows NT Service class library
|
|
Copyright Abandoned 1998 Irena Pancirov - Irnet Snc
|
|
This file is public domain and comes with NO WARRANTY of any kind
|
|
-------------------------------------------------------------------------- */
|
|
#include <windows.h>
|
|
#include <process.h>
|
|
#include <stdio.h>
|
|
#include "nt_servc.h"
|
|
|
|
|
|
static NTService *pService;
|
|
|
|
/* ------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------- */
|
|
NTService::NTService()
|
|
{
|
|
|
|
bOsNT = FALSE;
|
|
//service variables
|
|
ServiceName = NULL;
|
|
hExitEvent = 0;
|
|
bPause = FALSE;
|
|
bRunning = FALSE;
|
|
hThreadHandle = 0;
|
|
fpServiceThread = NULL;
|
|
|
|
//time-out variables
|
|
nStartTimeOut = 15000;
|
|
nStopTimeOut = 86400000;
|
|
nPauseTimeOut = 5000;
|
|
nResumeTimeOut = 5000;
|
|
|
|
//install variables
|
|
dwDesiredAccess = SERVICE_ALL_ACCESS;
|
|
dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
dwStartType = SERVICE_AUTO_START;
|
|
dwErrorControl = SERVICE_ERROR_NORMAL;
|
|
szLoadOrderGroup = NULL;
|
|
lpdwTagID = NULL;
|
|
szDependencies = NULL;
|
|
|
|
my_argc = 0;
|
|
my_argv = NULL;
|
|
hShutdownEvent = 0;
|
|
nError = 0;
|
|
dwState = 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------- */
|
|
NTService::~NTService()
|
|
{
|
|
if (ServiceName != NULL) delete[] ServiceName;
|
|
}
|
|
/* ------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------- */
|
|
|
|
BOOL NTService::GetOS()
|
|
{
|
|
bOsNT = FALSE;
|
|
memset(&osVer, 0, sizeof(OSVERSIONINFO));
|
|
osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (GetVersionEx(&osVer))
|
|
{
|
|
if (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
bOsNT = TRUE;
|
|
}
|
|
return bOsNT;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------
|
|
Init() Registers the main service thread with the service manager
|
|
|
|
ServiceThread - pointer to the main programs entry function
|
|
when the service is started
|
|
-------------------------------------------------------------------------- */
|
|
|
|
long NTService::Init(LPCSTR szInternName,void *ServiceThread)
|
|
{
|
|
|
|
pService = this;
|
|
|
|
fpServiceThread = (THREAD_FC)ServiceThread;
|
|
ServiceName = new char[lstrlen(szInternName)+1];
|
|
lstrcpy(ServiceName,szInternName);
|
|
|
|
SERVICE_TABLE_ENTRY stb[] =
|
|
{
|
|
{ (char *)szInternName,(LPSERVICE_MAIN_FUNCTION) ServiceMain} ,
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
return StartServiceCtrlDispatcher(stb); //register with the Service Manager
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------
|
|
Install() - Installs the service with Service manager
|
|
nError values:
|
|
0 success
|
|
1 Can't open the Service manager
|
|
2 Failed to create service
|
|
-------------------------------------------------------------------------- */
|
|
|
|
BOOL NTService::Install(int startType, LPCSTR szInternName,
|
|
LPCSTR szDisplayName,
|
|
LPCSTR szFullPath, LPCSTR szAccountName,
|
|
LPCSTR szPassword)
|
|
{
|
|
BOOL ret_val=FALSE;
|
|
SC_HANDLE newService, scm;
|
|
|
|
if (!SeekStatus(szInternName,1))
|
|
return FALSE;
|
|
|
|
char szFilePath[_MAX_PATH];
|
|
GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
|
|
|
|
// open a connection to the SCM
|
|
if (!(scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
|
|
printf("Failed to install the service (Couldn't open the SCM)\n");
|
|
else // Install the new service
|
|
{
|
|
if (!(newService=
|
|
CreateService(scm,
|
|
szInternName,
|
|
szDisplayName,
|
|
dwDesiredAccess,//default: SERVICE_ALL_ACCESS
|
|
dwServiceType, //default: SERVICE_WIN32_OWN_PROCESS
|
|
//default: SERVICE_AUTOSTART
|
|
(startType == 1 ? SERVICE_AUTO_START :
|
|
SERVICE_DEMAND_START),
|
|
dwErrorControl, //default: SERVICE_ERROR_NORMAL
|
|
szFullPath, //exec full path
|
|
szLoadOrderGroup, //default: NULL
|
|
lpdwTagID, //default: NULL
|
|
szDependencies, //default: NULL
|
|
szAccountName, //default: NULL
|
|
szPassword))) //default: NULL
|
|
printf("Failed to install the service (Couldn't create service)\n");
|
|
else
|
|
{
|
|
printf("Service successfully installed.\n");
|
|
CloseServiceHandle(newService);
|
|
ret_val=TRUE; // Everything went ok
|
|
}
|
|
CloseServiceHandle(scm);
|
|
}
|
|
return ret_val;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------
|
|
Remove() - Removes the service
|
|
nError values:
|
|
0 success
|
|
1 Can't open the Service manager
|
|
2 Failed to locate service
|
|
3 Failed to delete service
|
|
-------------------------------------------------------------------------- */
|
|
|
|
BOOL NTService::Remove(LPCSTR szInternName)
|
|
{
|
|
BOOL ret_value=FALSE;
|
|
SC_HANDLE service, scm;
|
|
|
|
if (!SeekStatus(szInternName,0))
|
|
return FALSE;
|
|
|
|
nError=0;
|
|
|
|
// open a connection to the SCM
|
|
if (!(scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
|
|
{
|
|
printf("Failed to remove the service (Couldn't open the SCM)\n");
|
|
}
|
|
else
|
|
{
|
|
if ((service = OpenService(scm,szInternName, DELETE)))
|
|
{
|
|
if (!DeleteService(service))
|
|
printf("Failed to remove the service\n");
|
|
else
|
|
{
|
|
printf("Service successfully removed.\n");
|
|
ret_value=TRUE; // everything went ok
|
|
}
|
|
CloseServiceHandle(service);
|
|
}
|
|
else
|
|
printf("Failed to remove the service (Couldn't open the service)\n");
|
|
CloseServiceHandle(scm);
|
|
}
|
|
return ret_value;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
Stop() - this function should be called before the app. exits to stop
|
|
the service
|
|
-------------------------------------------------------------------------- */
|
|
void NTService::Stop(void)
|
|
{
|
|
SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1, 60000);
|
|
StopService();
|
|
SetStatus(SERVICE_STOPPED, NO_ERROR, 0, 1, 1000);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
ServiceMain() - This is the function that is called from the
|
|
service manager to start the service
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void NTService::ServiceMain(DWORD argc, LPTSTR *argv)
|
|
{
|
|
|
|
// registration function
|
|
if (!(pService->hServiceStatusHandle =
|
|
RegisterServiceCtrlHandler(pService->ServiceName,
|
|
(LPHANDLER_FUNCTION)
|
|
NTService::ServiceCtrlHandler)))
|
|
goto error;
|
|
|
|
// notify SCM of progress
|
|
if (!pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 1, 8000))
|
|
goto error;
|
|
|
|
// create the exit event
|
|
if (!(pService->hExitEvent = CreateEvent (0, TRUE, FALSE,0)))
|
|
goto error;
|
|
|
|
if (!pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 3,
|
|
pService->nStartTimeOut))
|
|
goto error;
|
|
|
|
// save start arguments
|
|
pService->my_argc=argc;
|
|
pService->my_argv=argv;
|
|
|
|
// start the service
|
|
if (!pService->StartService())
|
|
goto error;
|
|
|
|
// Check that the service is now running.
|
|
if (!pService->SetStatus(SERVICE_RUNNING,NO_ERROR, 0, 0, 0))
|
|
goto error;
|
|
|
|
// wait for exit event
|
|
WaitForSingleObject (pService->hExitEvent, INFINITE);
|
|
|
|
// wait for thread to exit
|
|
if (WaitForSingleObject (pService->hThreadHandle, INFINITE) == WAIT_TIMEOUT)
|
|
CloseHandle(pService->hThreadHandle);
|
|
|
|
pService->Exit(0);
|
|
return;
|
|
|
|
error:
|
|
pService->Exit(GetLastError());
|
|
return;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
StartService() - starts the appliaction thread
|
|
-------------------------------------------------------------------------- */
|
|
|
|
BOOL NTService::StartService()
|
|
{
|
|
// Start the real service's thread (application)
|
|
if (!(hThreadHandle = (HANDLE) _beginthread((THREAD_FC)fpServiceThread,0,
|
|
(void *) this)))
|
|
return FALSE;
|
|
bRunning = TRUE;
|
|
return TRUE;
|
|
}
|
|
/* ------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------- */
|
|
void NTService::StopService()
|
|
{
|
|
bRunning=FALSE;
|
|
|
|
// Set the event for application
|
|
if (hShutdownEvent)
|
|
SetEvent(hShutdownEvent);
|
|
|
|
// Set the event for ServiceMain
|
|
SetEvent(hExitEvent);
|
|
}
|
|
/* ------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------- */
|
|
void NTService::PauseService()
|
|
{
|
|
bPause = TRUE;
|
|
SuspendThread(hThreadHandle);
|
|
}
|
|
/* ------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------- */
|
|
void NTService::ResumeService()
|
|
{
|
|
bPause=FALSE;
|
|
ResumeThread(hThreadHandle);
|
|
}
|
|
/* ------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------- */
|
|
BOOL NTService::SetStatus (DWORD dwCurrentState,DWORD dwWin32ExitCode,
|
|
DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,
|
|
DWORD dwWaitHint)
|
|
{
|
|
BOOL bRet;
|
|
SERVICE_STATUS serviceStatus;
|
|
|
|
dwState=dwCurrentState;
|
|
|
|
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
serviceStatus.dwCurrentState = dwCurrentState;
|
|
|
|
if (dwCurrentState == SERVICE_START_PENDING)
|
|
serviceStatus.dwControlsAccepted = 0; //don't accept control events
|
|
else
|
|
serviceStatus.dwControlsAccepted = (SERVICE_ACCEPT_STOP |
|
|
SERVICE_ACCEPT_PAUSE_CONTINUE |
|
|
SERVICE_ACCEPT_SHUTDOWN);
|
|
|
|
// if a specific exit code is defined,set up the win32 exit code properly
|
|
if (dwServiceSpecificExitCode == 0)
|
|
serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
|
|
else
|
|
serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
|
|
|
|
serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
|
|
|
|
serviceStatus.dwCheckPoint = dwCheckPoint;
|
|
serviceStatus.dwWaitHint = dwWaitHint;
|
|
|
|
// Pass the status to the Service Manager
|
|
if (!(bRet=SetServiceStatus (hServiceStatusHandle, &serviceStatus)))
|
|
StopService();
|
|
|
|
return bRet;
|
|
}
|
|
/* ------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------- */
|
|
void NTService::ServiceCtrlHandler(DWORD ctrlCode)
|
|
{
|
|
DWORD dwState;
|
|
|
|
if (!pService)
|
|
return;
|
|
|
|
dwState=pService->dwState; // get current state
|
|
|
|
switch(ctrlCode) {
|
|
|
|
#ifdef NOT_USED /* do we need this ? */
|
|
case SERVICE_CONTROL_PAUSE:
|
|
if (pService->bRunning && ! pService->bPause)
|
|
{
|
|
dwState = SERVICE_PAUSED;
|
|
pService->SetStatus(SERVICE_PAUSE_PENDING,NO_ERROR, 0, 1,
|
|
pService->nPauseTimeOut);
|
|
pService->PauseService();
|
|
}
|
|
break;
|
|
|
|
case SERVICE_CONTROL_CONTINUE:
|
|
if (pService->bRunning && pService->bPause)
|
|
{
|
|
dwState = SERVICE_RUNNING;
|
|
pService->SetStatus(SERVICE_CONTINUE_PENDING,NO_ERROR, 0, 1,
|
|
pService->nResumeTimeOut);
|
|
pService->ResumeService();
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case SERVICE_CONTROL_SHUTDOWN:
|
|
case SERVICE_CONTROL_STOP:
|
|
dwState = SERVICE_STOP_PENDING;
|
|
pService->SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1,
|
|
pService->nStopTimeOut);
|
|
pService->StopService();
|
|
break;
|
|
|
|
default:
|
|
pService->SetStatus(dwState, NO_ERROR,0, 0, 0);
|
|
break;
|
|
}
|
|
//pService->SetStatus(dwState, NO_ERROR,0, 0, 0);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void NTService::Exit(DWORD error)
|
|
{
|
|
if (hExitEvent)
|
|
CloseHandle(hExitEvent);
|
|
|
|
// Send a message to the scm to tell that we stop
|
|
if (hServiceStatusHandle)
|
|
SetStatus(SERVICE_STOPPED, error,0, 0, 0);
|
|
|
|
// If the thread has started kill it ???
|
|
// if (hThreadHandle) CloseHandle(hThreadHandle);
|
|
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------- */
|
|
|
|
BOOL NTService::SeekStatus(LPCSTR szInternName, int OperationType)
|
|
{
|
|
BOOL ret_value=FALSE;
|
|
SC_HANDLE service, scm;
|
|
|
|
// open a connection to the SCM
|
|
if (!(scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
|
|
{
|
|
DWORD ret_error=GetLastError();
|
|
if (ret_error == ERROR_ACCESS_DENIED)
|
|
{
|
|
printf("Install/Remove of the Service Denied!\n");
|
|
if(!is_super_user())
|
|
printf("That operation should be made by an user with Administrator privileges!\n");
|
|
}
|
|
else
|
|
printf("There is a problem for to open the Service Control Manager!\n");
|
|
}
|
|
else
|
|
{
|
|
if (OperationType == 1)
|
|
{
|
|
/* an install operation */
|
|
if ((service = OpenService(scm,szInternName, SERVICE_ALL_ACCESS )))
|
|
{
|
|
LPQUERY_SERVICE_CONFIG ConfigBuf;
|
|
DWORD dwSize;
|
|
|
|
ConfigBuf = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 4096);
|
|
printf("The service already exists!\n");
|
|
if (QueryServiceConfig(service,ConfigBuf,4096,&dwSize))
|
|
printf("The current server installed: %s\n",
|
|
ConfigBuf->lpBinaryPathName);
|
|
LocalFree(ConfigBuf);
|
|
CloseServiceHandle(service);
|
|
}
|
|
else
|
|
ret_value=TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* a remove operation */
|
|
if (!(service = OpenService(scm,szInternName, SERVICE_ALL_ACCESS )))
|
|
printf("The service doesn't exists!\n");
|
|
else
|
|
{
|
|
SERVICE_STATUS ss;
|
|
|
|
memset(&ss, 0, sizeof(ss));
|
|
if (QueryServiceStatus(service,&ss))
|
|
{
|
|
DWORD dwState = ss.dwCurrentState;
|
|
if (dwState == SERVICE_RUNNING)
|
|
printf("Failed to remove the service because the service is running\nStop the service and try again\n");
|
|
else if (dwState == SERVICE_STOP_PENDING)
|
|
printf("\
|
|
Failed to remove the service because the service is in stop pending state!\n\
|
|
Wait 30 seconds and try again.\n\
|
|
If this condition persist, reboot the machine and try again\n");
|
|
else
|
|
ret_value= TRUE;
|
|
}
|
|
CloseServiceHandle(service);
|
|
}
|
|
}
|
|
CloseServiceHandle(scm);
|
|
}
|
|
|
|
return ret_value;
|
|
}
|
|
/* ------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------- */
|
|
BOOL NTService::IsService(LPCSTR ServiceName)
|
|
{
|
|
BOOL ret_value=FALSE;
|
|
SC_HANDLE service, scm;
|
|
|
|
if (scm = OpenSCManager(0, 0,SC_MANAGER_ENUMERATE_SERVICE))
|
|
{
|
|
if ((service = OpenService(scm,ServiceName, SERVICE_ALL_ACCESS )))
|
|
{
|
|
ret_value=TRUE;
|
|
CloseServiceHandle(service);
|
|
}
|
|
CloseServiceHandle(scm);
|
|
}
|
|
return ret_value;
|
|
}
|
|
/* ------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------- */
|
|
BOOL NTService::got_service_option(char **argv, char *service_option)
|
|
{
|
|
char *option;
|
|
for (option= argv[1]; *option; option++)
|
|
if (!strcmp(option, service_option))
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
/* ------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------- */
|
|
BOOL NTService::is_super_user()
|
|
{
|
|
HANDLE hAccessToken;
|
|
UCHAR InfoBuffer[1024];
|
|
PTOKEN_GROUPS ptgGroups=(PTOKEN_GROUPS)InfoBuffer;
|
|
DWORD dwInfoBufferSize;
|
|
PSID psidAdministrators;
|
|
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
|
|
UINT x;
|
|
BOOL ret_value=FALSE;
|
|
|
|
if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,&hAccessToken ))
|
|
{
|
|
if(GetLastError() != ERROR_NO_TOKEN)
|
|
return FALSE;
|
|
|
|
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hAccessToken))
|
|
return FALSE;
|
|
}
|
|
|
|
ret_value= GetTokenInformation(hAccessToken,TokenGroups,InfoBuffer,
|
|
1024, &dwInfoBufferSize);
|
|
|
|
CloseHandle(hAccessToken);
|
|
|
|
if(!ret_value )
|
|
return FALSE;
|
|
|
|
if(!AllocateAndInitializeSid(&siaNtAuthority, 2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&psidAdministrators))
|
|
return FALSE;
|
|
|
|
ret_value = FALSE;
|
|
|
|
for(x=0;x<ptgGroups->GroupCount;x++)
|
|
{
|
|
if( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) )
|
|
{
|
|
ret_value = TRUE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
FreeSid(psidAdministrators);
|
|
return ret_value;
|
|
}
|