summaryrefslogtreecommitdiffstats
path: root/ldap/synctools/passwordsync/passsync/ntservice.cpp
diff options
context:
space:
mode:
authorDavid Boreham <dboreham@redhat.com>2005-03-11 02:44:17 +0000
committerDavid Boreham <dboreham@redhat.com>2005-03-11 02:44:17 +0000
commita957eeb8962ee1611b2546fda2bb11a5c909e59b (patch)
treea954c178f40f3531a52b01227c48e7a2df8d8894 /ldap/synctools/passwordsync/passsync/ntservice.cpp
parent9a7d1e1fd10a644ed17952acd18f755470d4744a (diff)
downloadds-a957eeb8962ee1611b2546fda2bb11a5c909e59b.tar.gz
ds-a957eeb8962ee1611b2546fda2bb11a5c909e59b.tar.xz
ds-a957eeb8962ee1611b2546fda2bb11a5c909e59b.zip
Merge over new code: fractional replication, wan replication and windows sync plus associated UI
Diffstat (limited to 'ldap/synctools/passwordsync/passsync/ntservice.cpp')
-rw-r--r--ldap/synctools/passwordsync/passsync/ntservice.cpp576
1 files changed, 576 insertions, 0 deletions
diff --git a/ldap/synctools/passwordsync/passsync/ntservice.cpp b/ldap/synctools/passwordsync/passsync/ntservice.cpp
new file mode 100644
index 00000000..6d0f1151
--- /dev/null
+++ b/ldap/synctools/passwordsync/passsync/ntservice.cpp
@@ -0,0 +1,576 @@
+/***********************************************************************
+**
+** Copyright 1996 - Netscape Communications Corporation
+**
+** NAME
+** NTService.cpp
+**
+** DESCRIPTION
+** Base class for NT Service app
+**
+** AUTHOR
+** Rob Weltman <rweltman@netscape.com>
+**
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+// Removed: 2-8-2005
+//#include "sysplat.h"
+// Added: 2-8-2005
+#include <stdio.h>
+// End Change
+
+#include <tchar.h>
+#include <time.h>
+#include "NTService.h"
+// Remove: 2-8-2005
+//#include "uniutil.h"
+// End Change
+#include "dssynchmsg.h"
+
+// static variables
+CNTService* CNTService::m_pThis = NULL;
+
+CNTService::CNTService(const TCHAR* szServiceName)
+{
+ // copy the address of the current object so we can access it from
+ // the static member callback functions.
+ // WARNING: This limits the application to only one CNTService object.
+ m_pThis = this;
+
+ // Set the default service name and version
+ _tcsncpy(m_szServiceName, szServiceName, sizeof(m_szServiceName)-1);
+ m_iMajorVersion = 1;
+ m_iMinorVersion = 0;
+ m_hEventSource = NULL;
+
+ // set up the initial service status
+ m_hServiceStatus = NULL;
+ m_Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ m_Status.dwCurrentState = SERVICE_STOPPED;
+ m_Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+ m_Status.dwWin32ExitCode = 0;
+ m_Status.dwServiceSpecificExitCode = 0;
+ m_Status.dwCheckPoint = 0;
+ m_Status.dwWaitHint = 0;
+ m_bIsRunning = FALSE;
+}
+
+CNTService::~CNTService()
+{
+ DebugMsg(_T("CNTService::~CNTService()"));
+ if (m_hEventSource) {
+ ::DeregisterEventSource(m_hEventSource);
+ m_hEventSource = NULL;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Default command line argument parsing
+
+// Returns TRUE if it found an arg it recognised, FALSE if not
+// Note: processing some arguments causes output to stdout to be generated.
+BOOL CNTService::ParseStandardArgs(int argc, char* argv[])
+{
+ // See if we have any command line args we recognise
+ if (argc <= 1) return FALSE;
+
+ if (_stricmp(argv[1], "-v") == 0) {
+
+ // Spit out version info
+ _tprintf(_T("%s Version %d.%d\n"),
+ m_szServiceName, m_iMajorVersion, m_iMinorVersion);
+ _tprintf(_T("The service is %s installed\n"),
+ IsInstalled() ? _T("currently") : _T("not"));
+ return TRUE; // say we processed the argument
+
+ } else if (_stricmp(argv[1], "-i") == 0) {
+
+ // Request to install.
+ if (IsInstalled()) {
+ _tprintf(_T("%s is already installed\n"), m_szServiceName);
+ } else {
+ // Try and install the copy that's running
+ if (Install()) {
+ _tprintf(_T("%s installed\n"), m_szServiceName);
+ } else {
+ _tprintf(_T("%s failed to install. Error %d\n"),
+ m_szServiceName, GetLastError());
+ }
+ }
+ return TRUE; // say we processed the argument
+
+ } else if (_stricmp(argv[1], "-u") == 0) {
+
+ // Request to uninstall.
+ if (!IsInstalled()) {
+ _tprintf(_T("%s is not installed\n"), m_szServiceName);
+ } else {
+ // Try and remove the copy that's installed
+ if (Uninstall()) {
+ // Get the executable file path
+ TCHAR szFilePath[_MAX_PATH];
+ ::GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
+ _tprintf(_T("%s removed. (You must delete the file (%s) yourself.)\n"),
+ m_szServiceName, szFilePath);
+ } else {
+ _tprintf(_T("Could not remove %s. Error %d\n"),
+ m_szServiceName, GetLastError());
+ }
+ }
+ return TRUE; // say we processed the argument
+
+ }
+
+ // Don't recognise the args
+ return FALSE;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Install/uninstall routines
+
+// Test if the service is currently installed
+BOOL CNTService::IsInstalled()
+{
+ BOOL bResult = FALSE;
+
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine
+ NULL, // ServicesActive database
+ SC_MANAGER_ALL_ACCESS); // full access
+ if (hSCM) {
+
+ // Try to open the service
+ SC_HANDLE hService = ::OpenService(hSCM,
+ m_szServiceName,
+ SERVICE_QUERY_CONFIG);
+ if (hService) {
+ bResult = TRUE;
+ ::CloseServiceHandle(hService);
+ }
+
+ ::CloseServiceHandle(hSCM);
+ }
+
+ return bResult;
+}
+
+BOOL CNTService::Install()
+{
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine
+ NULL, // ServicesActive database
+ SC_MANAGER_ALL_ACCESS); // full access
+ if (!hSCM) return FALSE;
+
+ // Get the executable file path
+ TCHAR szFilePath[_MAX_PATH];
+ ::GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)/sizeof(*szFilePath));
+
+ // Create the service
+ SC_HANDLE hService = ::CreateService(hSCM,
+ m_szServiceName,
+ m_szServiceName,
+ SERVICE_ALL_ACCESS,
+ SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_DEMAND_START, // start condition
+ SERVICE_ERROR_NORMAL,
+ szFilePath,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (!hService) {
+ ::CloseServiceHandle(hSCM);
+ return FALSE;
+ }
+
+ // make registry entries to support logging messages
+ // Add the source name as a subkey under the Application
+ // key in the EventLog service portion of the registry.
+ TCHAR szKey[256];
+ HKEY hKey = NULL;
+ _tcscpy(szKey, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\"));
+ _tcscat(szKey, GetEventName());
+ if (::RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) {
+ ::CloseServiceHandle(hService);
+ ::CloseServiceHandle(hSCM);
+ return FALSE;
+ }
+
+ // Add the Event ID message-file name to the 'EventMessageFile' subkey.
+ ::RegSetValueEx(hKey,
+ _T("EventMessageFile"),
+ 0,
+ REG_EXPAND_SZ,
+ (CONST BYTE*)szFilePath,
+ (_tcslen(szFilePath) + 1)*sizeof(*szFilePath));
+
+ // Set the supported types flags.
+ DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
+ ::RegSetValueEx(hKey,
+ _T("TypesSupported"),
+ 0,
+ REG_DWORD,
+ (CONST BYTE*)&dwData,
+ sizeof(DWORD));
+ ::RegCloseKey(hKey);
+
+ LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_INSTALLED, m_szServiceName);
+
+ // tidy up
+ ::CloseServiceHandle(hService);
+ ::CloseServiceHandle(hSCM);
+ return TRUE;
+}
+
+BOOL CNTService::Uninstall()
+{
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine
+ NULL, // ServicesActive database
+ SC_MANAGER_ALL_ACCESS); // full access
+ if (!hSCM) return FALSE;
+
+ BOOL bResult = FALSE;
+ SC_HANDLE hService = ::OpenService(hSCM,
+ m_szServiceName,
+ DELETE);
+ if (hService) {
+ // Stop it if it is running
+ SERVICE_STATUS serviceStatus;
+ BOOL bStop = ControlService( hService, SERVICE_CONTROL_STOP,
+ &serviceStatus );
+ if (::DeleteService(hService)) {
+ LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_REMOVED, m_szServiceName);
+ bResult = TRUE;
+ } else {
+ LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_NOTREMOVED, m_szServiceName);
+ }
+ ::CloseServiceHandle(hService);
+ }
+
+ ::CloseServiceHandle(hSCM);
+ return bResult;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+// Logging functions
+
+// This function makes an entry into the application event log
+void CNTService::LogEvent(WORD wType, DWORD dwID,
+ const wchar_t* pszS1,
+ const wchar_t* pszS2,
+ const wchar_t* pszS3)
+{
+#ifndef _DEBUG
+ if ( EVMSG_DEBUG == dwID )
+ return;
+#endif
+ const wchar_t* ps[3];
+ ps[0] = pszS1;
+ ps[1] = pszS2;
+ ps[2] = pszS3;
+
+ int iStr = 0;
+ for (int i = 0; i < 3; i++) {
+ if (ps[i] != NULL) iStr++;
+ }
+
+ // Check the event source has been registered and if
+ // not then register it now
+ if (!m_hEventSource) {
+ TCHAR *name = GetEventName();
+// Modification: 2-8-2005
+// m_hEventSource = ::RegisterEventSourceW(NULL, // local machine
+// GetEventName()); // source name
+ m_hEventSource = ::RegisterEventSourceW(NULL, // local machine
+ (const unsigned short *)GetEventName()); // source name
+// End Change
+ }
+
+ if (m_hEventSource) {
+ ::ReportEventW(m_hEventSource,
+ wType,
+ 0,
+ dwID,
+ NULL, // sid
+ iStr,
+ 0,
+ ps,
+ NULL);
+ }
+}
+
+// This function makes an entry into the application event log
+void CNTService::LogEvent(WORD wType, DWORD dwID,
+ const char* pszS1,
+ const char* pszS2,
+ const char* pszS3)
+{
+ wchar_t *p1 = pszS1 ? StrToUnicode( pszS1 ) : NULL;
+ wchar_t *p2 = pszS2 ? StrToUnicode( pszS2 ) : NULL;
+ wchar_t *p3 = pszS3 ? StrToUnicode( pszS3 ) : NULL;
+ LogEvent( wType, dwID, p1, p2, p3 );
+ if ( p1 )
+ free( p1 );
+ if ( p2 )
+ free( p2 );
+ if ( p3 )
+ free( p3 );
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+// Service startup and registration
+
+BOOL CNTService::StartService()
+{
+ CNTService* pService = m_pThis;
+ SERVICE_TABLE_ENTRY st[] = {
+ {m_szServiceName, ServiceMain},
+ {NULL, NULL}
+ };
+
+ DebugMsg(_T("Calling StartServiceCtrlDispatcher()"));
+ // Fails if started from command line, but StartService
+ // works any way
+ BOOL b = ::StartServiceCtrlDispatcher(st);
+ DWORD err = GetLastError();
+ DebugMsg(_T("Returned from StartServiceCtrlDispatcher()"));
+ return b;
+}
+
+BOOL CNTService::StartServiceDirect()
+{
+ BOOL b = FALSE;
+
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine
+ NULL, // ServicesActive database
+ SC_MANAGER_ALL_ACCESS); // full access
+ if (!hSCM) return FALSE;
+ SC_HANDLE hService = ::OpenService(hSCM,
+ m_szServiceName,
+ SERVICE_START);
+ if (hService)
+ {
+ DebugMsg(_T("Calling StartServiceDirect()"));
+ b = ::StartService( hService, 0, NULL );
+ ::CloseServiceHandle(hService);
+ }
+ ::CloseServiceHandle(hSCM);
+
+ return b;
+}
+
+// static member function (callback)
+void CNTService::ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
+{
+ // Get a pointer to the C++ object
+ CNTService* pService = m_pThis;
+
+ pService->DebugMsg(_T("Entering CNTService::ServiceMain()"));
+ // Register the control request handler
+ pService->m_Status.dwCurrentState = SERVICE_START_PENDING;
+ pService->m_hServiceStatus = RegisterServiceCtrlHandler(pService->m_szServiceName,
+ Handler);
+ if (pService->m_hServiceStatus == NULL) {
+ pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_CTRLHANDLERNOTINSTALLED);
+ return;
+ }
+
+ // Start the initialisation
+ if (pService->Initialize()) {
+
+ // Do the real work.
+ // When the Run function returns, the service has stopped.
+ pService->m_bIsRunning = TRUE;
+ pService->m_Status.dwWin32ExitCode = 0;
+ pService->m_Status.dwCheckPoint = 0;
+ pService->m_Status.dwWaitHint = 0;
+ pService->Run();
+ }
+
+ // Tell the service manager we are stopped
+ pService->SetStatus(SERVICE_STOPPED);
+
+ pService->DebugMsg(_T("Leaving CNTService::ServiceMain()"));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// status functions
+
+void CNTService::SetStatus(DWORD dwState)
+{
+ DebugMsg(_T("CNTService::SetStatus(%lu, %lu)"), m_hServiceStatus, dwState);
+ m_Status.dwCurrentState = dwState;
+ ::SetServiceStatus(m_hServiceStatus, &m_Status);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// Service initialization
+
+BOOL CNTService::Initialize()
+{
+ DebugMsg(_T("Entering CNTService::Initialize()"));
+
+ // Start the initialization
+ SetStatus(SERVICE_START_PENDING);
+
+ // Perform the actual initialization
+ BOOL bResult = OnInit();
+
+ // Set final state
+ m_Status.dwWin32ExitCode = GetLastError();
+ m_Status.dwCheckPoint = 0;
+ m_Status.dwWaitHint = 0;
+ if (!bResult) {
+ LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_FAILEDINIT);
+ SetStatus(SERVICE_STOPPED);
+ return FALSE;
+ }
+
+ LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_STARTED);
+ SetStatus(SERVICE_RUNNING);
+
+ DebugMsg(_T("Leaving CNTService::Initialize()"));
+ return TRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// main function to do the real work of the service
+
+// This function performs the main work of the service.
+// When this function returns the service has stopped.
+void CNTService::Run()
+{
+ DebugMsg(_T("Entering CNTService::Run()"));
+
+ while (m_bIsRunning) {
+ DebugMsg(_T("Sleeping..."));
+ Sleep(5000);
+ }
+
+ // nothing more to do
+ DebugMsg(_T("Leaving CNTService::Run()"));
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// Control request handlers
+
+// static member function (callback) to handle commands from the
+// service control manager
+void CNTService::Handler(DWORD dwOpcode)
+{
+ // Get a pointer to the object
+ CNTService* pService = m_pThis;
+
+ pService->DebugMsg(_T("CNTService::Handler(%lu)"), dwOpcode);
+ switch (dwOpcode) {
+ case SERVICE_CONTROL_STOP: // 1
+ pService->SetStatus(SERVICE_STOP_PENDING);
+ pService->OnStop();
+ pService->m_bIsRunning = FALSE;
+ pService->LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_STOPPED);
+ if (pService->m_hEventSource) {
+ ::DeregisterEventSource(pService->m_hEventSource);
+ pService->m_hEventSource = NULL;
+ }
+
+ break;
+
+ case SERVICE_CONTROL_PAUSE: // 2
+ pService->OnPause();
+ break;
+
+ case SERVICE_CONTROL_CONTINUE: // 3
+ pService->OnContinue();
+ break;
+
+ case SERVICE_CONTROL_INTERROGATE: // 4
+ pService->OnInterrogate();
+ break;
+
+ case SERVICE_CONTROL_SHUTDOWN: // 5
+ pService->OnShutdown();
+ break;
+
+ default:
+ if (dwOpcode >= SERVICE_CONTROL_USER) {
+ if (!pService->OnUserControl(dwOpcode)) {
+ pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_BADREQUEST);
+ }
+ } else {
+ pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_BADREQUEST);
+ }
+ break;
+ }
+
+ // Report current status
+ pService->DebugMsg(_T("Updating status (%lu, %lu)"),
+ pService->m_hServiceStatus,
+ pService->m_Status.dwCurrentState);
+ ::SetServiceStatus(pService->m_hServiceStatus, &pService->m_Status);
+}
+
+// Called when the service is first initialized
+BOOL CNTService::OnInit()
+{
+ DebugMsg(_T("CNTService::OnInit()"));
+ return TRUE;
+}
+
+// Called when the service control manager wants to stop the service
+void CNTService::OnStop()
+{
+ DebugMsg(_T("CNTService::OnStop()"));
+}
+
+// called when the service is interrogated
+void CNTService::OnInterrogate()
+{
+ DebugMsg(_T("CNTService::OnInterrogate()"));
+}
+
+// called when the service is paused
+void CNTService::OnPause()
+{
+ DebugMsg(_T("CNTService::OnPause()"));
+}
+
+// called when the service is continued
+void CNTService::OnContinue()
+{
+ DebugMsg(_T("CNTService::OnContinue()"));
+}
+
+// called when the service is shut down
+void CNTService::OnShutdown()
+{
+ DebugMsg(_T("CNTService::OnShutdown()"));
+}
+
+// called when the service gets a user control message
+BOOL CNTService::OnUserControl(DWORD dwOpcode)
+{
+ DebugMsg(_T("CNTService::OnUserControl(%8.8lXH)"), dwOpcode);
+ return FALSE; // say not handled
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// Debugging support
+
+void CNTService::DebugMsg(const TCHAR* pszFormat, ...)
+{
+ TCHAR buf[1024];
+ _stprintf(buf, _T("[%s](%lu): "), m_szServiceName, GetCurrentThreadId());
+ va_list arglist;
+ va_start(arglist, pszFormat);
+ _vstprintf(&buf[_tcslen(buf)], pszFormat, arglist);
+ va_end(arglist);
+ _tcscat(buf, _T("\n"));
+ OutputDebugString(buf);
+}