diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:07:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:07:14 +0000 |
commit | a175314c3e5827eb193872241446f2f8f5c9d33c (patch) | |
tree | cd3d60ca99ae00829c52a6ca79150a5b6e62528b /sql/nt_servc.cc | |
parent | Initial commit. (diff) | |
download | mariadb-10.5-upstream/1%10.5.12.tar.xz mariadb-10.5-upstream/1%10.5.12.zip |
Adding upstream version 1:10.5.12.upstream/1%10.5.12upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | sql/nt_servc.cc | 555 |
1 files changed, 555 insertions, 0 deletions
diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc new file mode 100644 index 00000000..9c754763 --- /dev/null +++ b/sql/nt_servc.cc @@ -0,0 +1,555 @@ +/** + @file + + @brief + 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 <stdlib.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; +} +/* ------------------------------------------------------------------------ + + -------------------------------------------------------------------------- */ + + +/** + Registers the main service thread with the service manager. + + @param ServiceThread pointer to the main programs entry function + when the service is started +*/ + + +long NTService::Init(LPCSTR szInternName, THREAD_FC ServiceThread) +{ + + pService = this; + + fpServiceThread = ServiceThread; + ServiceName = new char[lstrlen(szInternName)+1]; + lstrcpy(ServiceName,szInternName); + + SERVICE_TABLE_ENTRY stb[] = + { + { (char *)szInternName, ServiceMain} , + { NULL, NULL } + }; + + return StartServiceCtrlDispatcher(stb); //register with the Service Manager +} + + +/** + 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; +} + + +/** + 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; +} + +/** + 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); +} + +/** + 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, + 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; + + // 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; +} + + + +void NTService::SetRunning() +{ + if (pService) + pService->SetStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0); +} + +void NTService::SetSlowStarting(unsigned long timeout) +{ + if (pService) + pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 0, timeout); +} + + +/* ------------------------------------------------------------------------ + StartService() - starts the application thread + -------------------------------------------------------------------------- */ + +BOOL NTService::StartService() +{ + // Start the real service's thread (application) + if (!(hThreadHandle = (HANDLE) _beginthread(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) { + 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 exist!\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_QUERY_STATUS))) + { + ret_value=TRUE; + CloseServiceHandle(service); + } + CloseServiceHandle(scm); + } + return ret_value; +} +/* ------------------------------------------------------------------------ + -------------------------------------------------------------------------- */ +BOOL NTService::got_service_option(char **argv, const 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; +} |