// PURPOSE: Installs the service on the local machine void CNTService::CmdInstallService() { char szPath[_MAX_PATH * 2]; char szErr[256]; ReportEvent(EVENTLOG_INFORMATION_TYPE, 0, "Installing Service."); // Try to determine the name and path of this application. if ( !GetModuleFileName(NULL, szPath, sizeof(szPath)) ) { ReportEvent(EVENTLOG_ERROR_TYPE, 0, "Install GetModuleFileName", GetLastErrorText(szErr, sizeof(szErr))); return; } // Try to open the Service Control Manager SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if ( !schSCManager ) { ReportEvent(EVENTLOG_ERROR_TYPE, 0, "Install OpenSCManager", GetLastErrorText(szErr, sizeof(szErr))); return; } // Try to create the service char szInternalName[_MAX_PATH]; sprintf(szInternalName, SPHERE_TITLE " - %s", g_Serv.GetName()); SC_HANDLE schService = CreateService( schSCManager, // handle of the Service Control Manager szInternalName, // Internal name of the service (used when controlling the service using "net start" or "netsvc") szInternalName, // Display name of the service (displayed in the Control Panel | Services page) SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, // Start automatically when the OS starts SERVICE_ERROR_NORMAL, szPath, // Path and filename of this executable NULL, NULL, NULL, NULL, NULL ); if ( !schService ) { ReportEvent(EVENTLOG_ERROR_TYPE, 0, "Install CreateService", GetLastErrorText(szErr, sizeof(szErr))); bailout1: CloseServiceHandle(schSCManager); return; } // Configure service - Service description char szDescription[_MAX_PATH]; sprintf(szDescription, "SphereServer Service for %s", g_Serv.GetName()); SERVICE_DESCRIPTION sdDescription; sdDescription.lpDescription = szDescription; if ( !ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sdDescription) ) { // not critical, so no need to abort the service creation ReportEvent(EVENTLOG_WARNING_TYPE, 0, "Install SetDescription", GetLastErrorText(szErr, sizeof(szErr))); } // Configure service - Restart options SC_ACTION scAction[3]; scAction[0].Type = SC_ACTION_RESTART; // restart process on failure scAction[0].Delay = 10000; // wait 10 seconds before restarting scAction[1].Type = SC_ACTION_RESTART; scAction[1].Delay = 10000; scAction[2].Type = SC_ACTION_RESTART; // wait 2 minutes before restarting the third time scAction[2].Delay = 120000; SERVICE_FAILURE_ACTIONS sfaFailure; sfaFailure.dwResetPeriod = (1 * 60 * 60); // reset failure count after an hour passes with no fails sfaFailure.lpRebootMsg = NULL; // no reboot message sfaFailure.lpCommand = NULL; // no command executed sfaFailure.cActions = COUNTOF(scAction); // number of actions sfaFailure.lpsaActions = scAction; // if ( !ChangeServiceConfig2(schService, SERVICE_CONFIG_FAILURE_ACTIONS, &sfaFailure) ) { // not critical, so no need to abort the service creation ReportEvent(EVENTLOG_WARNING_TYPE, 0, "Install SetAutoRestart", GetLastErrorText(szErr, sizeof(szErr))); } HKEY hKey; char szKey[_MAX_PATH]; // Register the application for event logging DWORD dwData; // Try to create the registry key containing information about this application strcpy(szKey, "System\\CurrentControlSet\\Services\\EventLog\\Application\\" SPHERE_FILE "svr"); if (RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey)) ReportEvent(EVENTLOG_ERROR_TYPE, 0, "Install RegCreateKey", GetLastErrorText(szErr, sizeof(szErr))); else { // Try to create the registry key containing the name of the EventMessageFile // Replace the name of the exe with the name of the dll in the szPath variable if (RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) szPath, strlen(szPath) + 1)) ReportEvent(EVENTLOG_ERROR_TYPE, 0, "Install RegSetValueEx", GetLastErrorText(szErr, sizeof(szErr))); else { // Try to create the registry key containing the types of errors this application will generate dwData = EVENTLOG_ERROR_TYPE|EVENTLOG_INFORMATION_TYPE|EVENTLOG_WARNING_TYPE; if ( RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD)) ) ReportEvent(EVENTLOG_ERROR_TYPE, 0, "Install RegSetValueEx", GetLastErrorText(szErr, sizeof(szErr))); } RegCloseKey(hKey); } // Set the working path for the application sprintf(szKey, "System\\CurrentControlSet\\Services\\" SPHERE_TITLE " - %s\\Parameters", g_Serv.GetName()); if ( RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) ) { ReportEvent(EVENTLOG_ERROR_TYPE, 0, "Install RegCreateKey", GetLastErrorText(szErr, sizeof(szErr))); bailout2: CloseServiceHandle(schService); goto bailout1; } ExtractPath(szPath); if ( RegSetValueEx(hKey, "WorkingPath", 0, REG_SZ, (const unsigned char *) &szPath[0], strlen(szPath)) ) ReportEvent(EVENTLOG_ERROR_TYPE, 0, "Install RegSetValueEx", GetLastErrorText(szErr, sizeof(szErr))); ReportEvent(EVENTLOG_INFORMATION_TYPE, 0, "Install OK", g_Serv.GetName()); goto bailout2; }
// PURPOSE: starts the service. (synchronous) int CNTService::ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv) { ReportEvent(EVENTLOG_INFORMATION_TYPE, 0, "Service start pending."); // Service initialization report status to the service control manager. int rc = -1; if ( !SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, 3000) ) return rc; // Create the event object. The control handler function signals this event when it receives a "stop" control code m_hServerStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if ( !m_hServerStopEvent ) return rc; if ( !SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, 3000) ) { bailout1: CloseHandle(m_hServerStopEvent); return rc; } // Create the event object used in overlapped i/o HANDLE hEvents[2] = {NULL, NULL}; hEvents[0] = m_hServerStopEvent; hEvents[1] = CreateEvent(NULL, TRUE, FALSE, NULL); if ( !hEvents[1] ) goto bailout1; if ( !SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, 3000) ) { bailout2: CloseHandle(hEvents[1]); goto bailout1; } // Create a security descriptor that allows anyone to write to the pipe PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR) malloc(SECURITY_DESCRIPTOR_MIN_LENGTH); if ( !pSD ) goto bailout2; if ( !InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION) ) { bailout3: free(pSD); goto bailout2; } // Add a NULL descriptor ACL to the security descriptor if ( !SetSecurityDescriptorDacl(pSD, TRUE, NULL, FALSE) ) goto bailout3; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = TRUE; if ( !SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, 3000) ) goto bailout3; // Set the name of the named pipe this application uses. We create a named pipe to ensure that // only one instance of this application runs on the machine at a time. If there is an instance // running, it will own this pipe, and any further attempts to create the same named pipe will fail. char lpszPipeName[80]; sprintf(lpszPipeName, "\\\\.\\pipe\\" SPHERE_FILE "svr\\%s", g_Serv.GetName()); char szErr[256]; // Open the named pipe HANDLE hPipe = CreateNamedPipe(lpszPipeName, FILE_FLAG_OVERLAPPED|PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, 1, 0, 0, 1000, &sa); if ( hPipe == INVALID_HANDLE_VALUE ) { ReportEvent(EVENTLOG_ERROR_TYPE, 0, "Can't create named pipe. Check multi-instance?", GetLastErrorText(szErr, sizeof(szErr))); goto bailout3; } if ( SetServiceStatus(SERVICE_RUNNING, NO_ERROR, 0) ) { rc = Sphere_MainEntryPoint(dwArgc, lpszArgv); if ( !rc ) ReportEvent(EVENTLOG_INFORMATION_TYPE, 0, "service stopped", GetLastErrorText(szErr, sizeof(szErr))); else { char szMessage[80]; sprintf(szMessage, "%d.", rc); ReportEvent(EVENTLOG_ERROR_TYPE, 0, "service stopped abnormally", szMessage); } } else ReportEvent(EVENTLOG_ERROR_TYPE, 0, "ServiceStart failed."); CloseHandle(hPipe); goto bailout3; }