/*++ Copyright (c) 1999 Microsoft Corporation Module Name: main.c Abstract: This is the main entry point for the service control manager for the web dav mini-redir service. Author: Rohan Kumar [RohanK] 08-Feb-2000 Environment: User Mode - Win32 Revision History: --*/ #include "pch.h" #pragma hdrstop #include #include #include // // Allocate global data in this file. // #define GLOBAL_DATA_ALLOCATE #include "global.h" DWORD DavStop = 0; // // The amount of time in seconds a server entry is cached in the ServerNotFound // cache. // ULONG ServerNotFoundCacheLifeTimeInSec = 0; // // Should we accept/claim the OfficeWebServers and TahoeWebServers? // ULONG AcceptOfficeAndTahoeServers = 0; // // Should we LOCK (using the DAV LOCK Verb) the file on the server on the // CreateFile path when needed? To know when exactly a LOCK is sent to the // server, look at the (LOCKing) comments in the davcreat.c file. // ULONG DavSupportLockingOfFiles = 1; PSVCHOST_GLOBAL_DATA DavSvcsGlobalData; DWORD DavNotRunningAsAService( VOID ); DWORD WINAPI DavFakeServiceController( LPVOID Parameter ); BOOL DavCheckLUIDDeviceMapsEnabled( VOID ); VOID DavReadRegistryValues( VOID ); VOID WINAPI DavServiceHandler ( DWORD dwOpcode ) /*++ Routine Description: This function is called by the Service Controller at various times when the service is running. Arguments: dwOpcode - Reason for calling the service handler. Return Value: none. --*/ { DWORD err; switch (dwOpcode) { case SERVICE_CONTROL_SHUTDOWN: // // Lack of break is intentional! // case SERVICE_CONTROL_STOP: DavPrint((DEBUG_INIT, "DavServiceHandler: WebClient service is stopping.\n")); UpdateServiceStatus(SERVICE_STOP_PENDING); if (g_WorkersActive) { err = DavTerminateWorkerThreads(); if (err != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/DavTerminateWorkerThreads: " "Error Val = %u.\n", err)); } g_WorkersActive = FALSE; } if (g_RpcActive) { DavSvcsGlobalData->StopRpcServer(davclntrpc_ServerIfHandle); g_RpcActive = FALSE; } // // Close and free up the DAV stuff. // DavClose(); if (g_socketinit) { err = CleanupTheSocketInterface(); if (err != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/CleanupTheSocketInterface: " "Error Val = %u.\n", err)); } g_socketinit = FALSE; } if (DavReflectorHandle != NULL) { err = UMReflectorStop(DavReflectorHandle); if (err != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/UMReflectorStop: Error Val = %u.\n", err)); } err = UMReflectorUnregister(DavReflectorHandle); if (err != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/UMReflectorUnregister: Error Val = 0x%x.\n", err)); } DavReflectorHandle = NULL; } if (g_RedirLoaded) { err = WsUnloadRedir(); if (err != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/WsUnloadRedir: Error Val = %u.\n", err)); } g_RedirLoaded = FALSE; } if (g_DavServiceLockSet) { DeleteCriticalSection ( &(g_DavServiceLock) ); g_DavServiceLockSet = FALSE; } DavPrint((DEBUG_INIT, "DavServiceMain: WebClient service is stopped.\n")); UpdateServiceStatus(SERVICE_STOPPED); #if DBG DebugUninitialize(); #endif break; case SERVICE_CONTROL_INTERROGATE: // // Refresh our status to the SCM. // SetServiceStatus(g_hStatus, &g_status); break; default: // // This may not be needed, but refresh our status to the service // controller. // DavPrint((DEBUG_INIT, "DavServiceHandler: WebClient service received SCM " "Opcode = %08lx\n", dwOpcode)); ASSERT (g_hStatus); SetServiceStatus (g_hStatus, &g_status); break; } return; } VOID SvchostPushServiceGlobals( PSVCHOST_GLOBAL_DATA pGlobals ) { DavSvcsGlobalData = pGlobals; } VOID WINAPI ServiceMain ( DWORD dwNumServicesArgs, LPWSTR *lpServiceArgVectors ) /*++ Routine Description: This function is called by the Service Control Manager when starting this service. Arguments: dwNumServicesArgs - Number of arguments. lpServiceArgVectors - Array of arguments. Return Value: None. --*/ { DWORD err = ERROR_SUCCESS; DWORD exitErr = ERROR_SUCCESS; HKEY KeyHandle = NULL; ULONG maxThreads = 0, initialThreads = 0, RedirRegisterCount = 0; BOOL RunningAsAService = TRUE; #if DBG DebugInitialize(); #endif DavReadRegistryValues(); // // Make sure svchost.exe gave us the global data // ASSERT(DavSvcsGlobalData != NULL); #if DBG { DWORD cbP = 0; WCHAR m_szProfilePath[MAX_PATH]; cbP = GetEnvironmentVariable(L"USERPROFILE", m_szProfilePath, MAX_PATH); m_szProfilePath[cbP] = L'\0'; DavPrint((DEBUG_MISC, "DavServiceMain: USERPROFILE: %ws\n", m_szProfilePath)); } #endif g_RedirLoaded = FALSE; g_WorkersActive = FALSE; g_registeredService = FALSE; // // Initialize the SERVICE_STATUS structure g_status. // ZeroMemory (&g_status, sizeof(g_status)); g_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; g_status.dwControlsAccepted = (SERVICE_ACCEPT_STOP | SERVICE_CONTROL_SHUTDOWN); g_status.dwCheckPoint = 1; g_status.dwWaitHint = DAV_WAIT_HINT_TIME; DavPrint((DEBUG_MISC, "DavServiceMain: lpServiceArgVectors[0] = %ws\n", lpServiceArgVectors[0])); if ( lpServiceArgVectors[0] && ( wcscmp(lpServiceArgVectors[0], L"notservice") == 0 ) ) { DavPrint((DEBUG_MISC, "DavServiceMain: WebClient is not running as a Service.\n")); } else { DavPrint((DEBUG_MISC, "DavServiceMain: WebClient is running as a Service.\n")); try { InitializeCriticalSection ( &(g_DavServiceLock) ); } except(EXCEPTION_EXECUTE_HANDLER) { err = GetExceptionCode(); DavPrint((DEBUG_ERRORS, "DavServiceMain/InitializeCriticalSection: Exception Code =" " = %08lx.\n", err)); goto exitServiceMain; } g_DavServiceLockSet = TRUE; // // Register the service control handler. // g_hStatus = RegisterServiceCtrlHandler(SERVICE_DAVCLIENT, DavServiceHandler); if (g_hStatus) { g_registeredService = TRUE; DavPrint((DEBUG_INIT, "DavServiceMain: WebClient service is pending start.\n")); } else { DavPrint((DEBUG_INIT, "DavServiceMain: WebClient service failed to register.\n")); goto exitServiceMain; } } UpdateServiceStatus(SERVICE_START_PENDING); // // Attempt to load the mini-redir driver. If this fails, no point in us // starting up. // while (TRUE) { err = WsLoadRedir(); if (err == ERROR_SERVICE_ALREADY_RUNNING || err == ERROR_SUCCESS) { DavPrint((DEBUG_MISC, "DavServiceMain/WsLoadRedir. Succeeded\n")); break; } // // If the transports are not ready, the MiniRedir returns an // error STATUS_REDIRECTOR_NOT_STARTED which maps to the Win32 error // ERROR_PATH_NOT_FOUND. In this case we sleep for 3 seconds and try // again with the hope that the transports will be ready soon. Also, // we update the service status to inform the SCM that we are doing // some work. We try this 5 times (till RedirRegisterCount == 4) and // if are unsuccessful, we give up. // if (err == ERROR_PATH_NOT_FOUND) { RedirRegisterCount++; DavPrint((DEBUG_ERRORS, "DavServiceMain/WsLoadRedir. RedirRegisterCount = %d\n", RedirRegisterCount)); if (RedirRegisterCount >= 4) { DavPrint((DEBUG_ERRORS, "DavServiceMain/WsLoadRedir(1). Error Val = %d\n", err)); goto exitServiceMain; } // // Sleep for 3 seconds. // Sleep(3000); (g_status.dwCheckPoint)++; UpdateServiceStatus(SERVICE_START_PENDING); continue; } else { DavPrint((DEBUG_ERRORS, "DavServiceMain/WsLoadRedir(2). Error Val = %d\n", err)); goto exitServiceMain; } } g_RedirLoaded = TRUE; (g_status.dwCheckPoint)++; UpdateServiceStatus(SERVICE_START_PENDING); // // Initialize the global NT-style redirector device name string. // RtlInitUnicodeString(&RedirDeviceName, DD_DAV_DEVICE_NAME_U); // // Try to register the mini-redir. // err = UMReflectorRegister(DD_DAV_DEVICE_NAME_U, UMREFLECTOR_CURRENT_VERSION, &(DavReflectorHandle)); if ((DavReflectorHandle == NULL) || (err != ERROR_SUCCESS)) { if (err == ERROR_SUCCESS) { err = ERROR_BAD_DRIVER; } DavPrint((DEBUG_ERRORS, "DavServiceMain/UMReflectorRegister. Error Val = %d\n", err)); goto exitServiceMain; } (g_status.dwCheckPoint)++; UpdateServiceStatus(SERVICE_START_PENDING); // // Try to start the mini-redir. // err = UMReflectorStart(UMREFLECTOR_CURRENT_VERSION, DavReflectorHandle); if (err != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/UMReflectorStart. Error Val = %u.\n", err)); goto exitServiceMain; } (g_status.dwCheckPoint)++; UpdateServiceStatus(SERVICE_START_PENDING); // // Initialize the socket interface. // err = InitializeTheSocketInterface(); if (err != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/InitializeTheSocketInterface: Error Val = %u.\n", err)); goto exitServiceMain; } // // Setup the DAV/WinInet environment. // err = DavInit(); if (err != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/DavInit: Error Val = %u.\n", err)); goto exitServiceMain; } // // Start the worker thread. This will handle completion routines queued // from other worker threads and from the request ioctl threads. // err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, DAV_PARAMETERS_KEY, 0, KEY_QUERY_VALUE, &KeyHandle); if (err == ERROR_SUCCESS) { maxThreads = ReadDWord(KeyHandle, DAV_MAXTHREADS_KEY, DAV_MAXTHREADCOUNT_DEFAULT); initialThreads = ReadDWord(KeyHandle, DAV_THREADS_KEY, DAV_THREADCOUNT_DEFAULT); RegCloseKey(KeyHandle); } else { maxThreads = DAV_MAXTHREADCOUNT_DEFAULT; initialThreads = DAV_THREADCOUNT_DEFAULT; } (g_status.dwCheckPoint)++; UpdateServiceStatus(SERVICE_START_PENDING); err = DavInitWorkerThreads(initialThreads, maxThreads); if (err != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/DavInitWorkerThread: Error Val = %u.\n", err)); goto exitServiceMain; } g_WorkersActive = TRUE; (g_status.dwCheckPoint)++; UpdateServiceStatus(SERVICE_START_PENDING); g_LUIDDeviceMapsEnabled = DavCheckLUIDDeviceMapsEnabled(); // // Immediately report that we are running. All non-essential initialization // is deferred until we are called by clients to do some work. // DavPrint((DEBUG_INIT, "DavServiceMain: WebClient service is now running.\n")); (g_status.dwCheckPoint)++; UpdateServiceStatus(SERVICE_START_PENDING); // // Setup RPC server for this service. // if (!g_RpcActive) { err = DavSvcsGlobalData->StartRpcServer(L"DAV RPC SERVICE", davclntrpc_ServerIfHandle); if (err == STATUS_SUCCESS) { g_RpcActive = TRUE; } else { DavPrint((DEBUG_ERRORS, "DavServiceMain/SetupRpcServer: Error Val = %u.\n", err)); } } UpdateServiceStatus(SERVICE_RUNNING); return; exitServiceMain: if (g_WorkersActive) { exitErr = DavTerminateWorkerThreads(); if (exitErr != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/DavTerminateWorkerThreads: " "Error Val = %u.\n", exitErr)); } g_WorkersActive = FALSE; } // // Close and free up the DAV stuff. // DavClose(); if (g_socketinit) { exitErr = CleanupTheSocketInterface(); if (exitErr != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/CleanupTheSocketInterface: " "Error Val = %u.\n", exitErr)); } g_socketinit = FALSE; } if (g_RpcActive) { DavSvcsGlobalData->StopRpcServer(davclntrpc_ServerIfHandle); g_RpcActive = FALSE; } if (DavReflectorHandle != NULL) { exitErr = UMReflectorStop(DavReflectorHandle); if (exitErr != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/UMReflectorStop: Error Val = %u.\n", exitErr)); } exitErr = UMReflectorUnregister(DavReflectorHandle); if (exitErr != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/UMReflectorUnregister: Error Val = 0x%x.\n", exitErr)); } DavReflectorHandle = NULL; } if (g_RedirLoaded) { exitErr = WsUnloadRedir(); if (exitErr != ERROR_SUCCESS) { DavPrint((DEBUG_ERRORS, "DavServiceMain/WsUnloadRedir: Error Val = %u.\n", exitErr)); } g_RedirLoaded = FALSE; } if (g_DavServiceLockSet) { DeleteCriticalSection ( &(g_DavServiceLock) ); g_DavServiceLockSet = FALSE; } // // Let the SCM know why the service did not start. // if (err != NO_ERROR) { g_status.dwWin32ExitCode = err; g_status.dwServiceSpecificExitCode = NO_ERROR; UpdateServiceStatus(SERVICE_STOPPED); } DavPrint((DEBUG_INIT, "DavServiceMain: WebClient service is stopped.\n")); #if DBG DebugUninitialize(); #endif return; } DWORD DavNotRunningAsAService( VOID ) /*++ Routine Description: The DavClient is not being run as a Service. Arguments: None. Return Value: ERROR_SUCCESS - No problems. Win32 Error Code - Something went wrong. --*/ { DWORD WStatus = ERROR_SUCCESS; HANDLE Thread; DWORD ThreadId; PWCHAR NotSrv = L"notservice"; // // Create a thread for the fake service controller. // Thread = CreateThread( NULL, 0, DavFakeServiceController, 0, 0, &ThreadId ); if (Thread == NULL) { WStatus = GetLastError(); DavPrint((DEBUG_ERRORS, "DavNotRunningAsAService/CreateThread: Error Val = %d.\n", WStatus)); return WStatus; } // // Call the Sevice Main function of the DavClient service. // ServiceMain( 2, &(NotSrv) ); return WStatus; } DWORD WINAPI DavFakeServiceController( LPVOID Parameter ) /*++ Routine Description: The Fake service control for the DavClient when it is not running as a service. This is used to send a STOP signal to the DavClient. Arguments: Parameter - Dummy parameter. Return Value: ERROR_SUCCESS - No problems. --*/ { while (DavStop == 0) { Sleep(1000); } DavServiceHandler( SERVICE_CONTROL_STOP ); return 0; } BOOL DavCheckLUIDDeviceMapsEnabled( VOID ) /*++ Routine Description: This function calls NtQueryInformationProcess() to determine if LUID device maps are enabled Arguments: none Return Value: TRUE - LUID device maps are enabled FALSE - LUID device maps are disabled --*/ { NTSTATUS Status; ULONG LUIDDeviceMapsEnabled; BOOL Result; Status = NtQueryInformationProcess( NtCurrentProcess(), ProcessLUIDDeviceMapsEnabled, &LUIDDeviceMapsEnabled, sizeof(LUIDDeviceMapsEnabled), NULL ); if (!NT_SUCCESS( Status )) { Result = FALSE; } else { Result = (LUIDDeviceMapsEnabled != 0); } return( Result ); } VOID _cdecl main ( IN INT ArgC, IN PCHAR ArgV[] ) /*++ Routine Description: Main (DavClient) runs as either a service or an exe. Arguments: ArgC - Number of arguments. ArgV - Array of arguments. Return Value: ERROR_SUCCESS - No problems. Win32 Error Code - Something went wrong. --*/ { BOOL RunningAsAService = TRUE; BOOL ReturnVal = FALSE; SERVICE_TABLE_ENTRYW DavServiceTableEntry[] = { { SERVICE_DAVCLIENT, ServiceMain }, { NULL, NULL } }; // // Are we running as a service or an exe ? // if ( ArgV[1] != NULL ) { if ( strstr(ArgV[1], "notservice") != NULL) { RunningAsAService = FALSE; } } if (RunningAsAService) { ReturnVal = StartServiceCtrlDispatcher(DavServiceTableEntry); if ( !ReturnVal ) { DavPrint((DEBUG_ERRORS, "main/StartServiceCtrlDispatcher: Error Val = %d.\n", GetLastError())); } } else { DWORD WStatus; WStatus = DavNotRunningAsAService(); if ( WStatus != ERROR_SUCCESS ) { DavPrint((DEBUG_ERRORS, "main/DavNotRunningAsAService: Error Val = %d.\n", WStatus)); } } return; } VOID DavReadRegistryValues( VOID ) /*++ Routine Description: This function reads some values from the registry and sets the globals in the WebClient service. Arguments: None. Return Value: None. --*/ { ULONG WStatus = ERROR_SUCCESS; HKEY KeyHandle = NULL; ULONG ValueType = 0, ValueSize = 0; WStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DAV_PARAMETERS_KEY, 0, KEY_QUERY_VALUE, &(KeyHandle)); if (WStatus != ERROR_SUCCESS) { KeyHandle = NULL; ServerNotFoundCacheLifeTimeInSec = 60; AcceptOfficeAndTahoeServers = 0; WStatus = GetLastError(); DbgPrint("ERROR: DavReadRegistryValues/RegOpenKeyExW. WStatus = %d\n", WStatus); goto EXIT_THE_FUNCTION; } // // If we fail in getting the values from the registry, set them to default // values. // ValueSize = sizeof(ServerNotFoundCacheLifeTimeInSec); WStatus = RegQueryValueExW(KeyHandle, DAV_SERV_CACHE_VALUE, 0, &(ValueType), (LPBYTE)&(ServerNotFoundCacheLifeTimeInSec), &(ValueSize)); if (WStatus != ERROR_SUCCESS) { ServerNotFoundCacheLifeTimeInSec = 60; WStatus = GetLastError(); DbgPrint("ERROR: DavReadRegistryValues/RegQueryValueExW(1). WStatus = %d\n", WStatus); } ValueSize = sizeof(AcceptOfficeAndTahoeServers); WStatus = RegQueryValueExW(KeyHandle, DAV_ACCEPT_TAHOE_OFFICE_SERVERS, 0, &(ValueType), (LPBYTE)&(AcceptOfficeAndTahoeServers), &(ValueSize)); if (WStatus != ERROR_SUCCESS) { AcceptOfficeAndTahoeServers = 0; WStatus = GetLastError(); DbgPrint("ERROR: DavReadRegistryValues/RegQueryValueExW(2). WStatus = %d\n", WStatus); } ValueSize = sizeof(DavSupportLockingOfFiles); WStatus = RegQueryValueExW(KeyHandle, DAV_SUPPORT_LOCKING_OF_FILES, 0, &(ValueType), (LPBYTE)&(DavSupportLockingOfFiles), &(ValueSize)); if (WStatus != ERROR_SUCCESS) { DavSupportLockingOfFiles = 1; WStatus = GetLastError(); DbgPrint("ERROR: DavReadRegistryValues/RegQueryValueExW(3). WStatus = %d\n", WStatus); } ValueSize = sizeof(DavFileSizeLimitInBytes); WStatus = RegQueryValueExW(KeyHandle, DAV_FILE_SIZE_LIMIT, 0, &(ValueType), (LPBYTE)&(DavFileSizeLimitInBytes), &(ValueSize)); if (WStatus != ERROR_SUCCESS) { DavFileSizeLimitInBytes = 0x2faf080; WStatus = GetLastError(); DbgPrint("ERROR: DavReadRegistryValues/RegQueryValueExW(4). WStatus = %d\n", WStatus); } ValueSize = sizeof(DavFileAttributesLimitInBytes); WStatus = RegQueryValueExW(KeyHandle, DAV_ATTRIBUTES_SIZE_LIMIT, 0, &(ValueType), (LPBYTE)&(DavFileAttributesLimitInBytes), &(ValueSize)); if (WStatus != ERROR_SUCCESS) { DavFileAttributesLimitInBytes = 0xf4240; WStatus = GetLastError(); DbgPrint("ERROR: DavReadRegistryValues/RegQueryValueExW(5). WStatus = %d\n", WStatus); } EXIT_THE_FUNCTION: if (KeyHandle) { RegCloseKey(KeyHandle); } return; }