Author: ion
Date: Wed Aug 28 08:32:27 2013
New Revision: 59847
URL:
http://svn.reactos.org/svn/reactos?rev=59847&view=rev
Log:
[SVCHOST]: Implement a Windows-compatible (5.2 SP1) SvcHost.exe process, which can load
Windows services according to the information at
http://www.geoffchappell.com/studies/windows/win32/services/svchost/index.h…, using the
same callbacks and registry settings, including support for RPC over NPIPE, NetBIOS and
COM, with correct handling of Security, Threading, Locking and Stop Callbacks. Tested with
the current BITS and DHCP services, which still work (although they don't take
advantage of the new functionality).
Added:
trunk/reactos/base/services/svchost/globals.c (with props)
trunk/reactos/base/services/svchost/netbios.c (with props)
trunk/reactos/base/services/svchost/registry.c (with props)
trunk/reactos/base/services/svchost/rpcsrv.c (with props)
trunk/reactos/base/services/svchost/security.cxx (with props)
Modified:
trunk/reactos/base/services/svchost/CMakeLists.txt
trunk/reactos/base/services/svchost/svchost.c
trunk/reactos/base/services/svchost/svchost.h
Modified: trunk/reactos/base/services/svchost/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/svchost/CMak…
==============================================================================
--- trunk/reactos/base/services/svchost/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/base/services/svchost/CMakeLists.txt [iso-8859-1] Wed Aug 28 08:32:27
2013
@@ -1,6 +1,7 @@
-add_executable(svchost svchost.c svchost.rc)
+add_executable(svchost globals.c registry.c security.cxx rpcsrv.c netbios.c svchost.c
svchost.rc)
+target_link_libraries(svchost uuid)
set_module_type(svchost win32cui UNICODE)
-add_importlibs(svchost advapi32 msvcrt kernel32 ntdll)
+add_importlibs(svchost advapi32 netapi32 rpcrt4 ole32 kernel32 ntdll)
add_cd_file(TARGET svchost DESTINATION reactos/system32 FOR all)
Added: trunk/reactos/base/services/svchost/globals.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/svchost/glob…
==============================================================================
--- trunk/reactos/base/services/svchost/globals.c (added)
+++ trunk/reactos/base/services/svchost/globals.c [iso-8859-1] Wed Aug 28 08:32:27 2013
@@ -0,0 +1,299 @@
+/*
+ * PROJECT: ReactOS Service Host
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * FILE: base/services/svchost/globals.c
+ * PURPOSE: Functions to initialize global settings and support
+ * PROGRAMMERS: ReactOS Portable Systems Group
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "svchost.h"
+
+/* GLOBALS *******************************************************************/
+
+PSID NullSid, WorldSid, LocalSid, NetworkSid, InteractiveSid, ServiceLogonSid;
+PSID LocalSystemSid, LocalServiceSid, NetworkServiceSid, BuiltinDomainSid;
+PSID AuthenticatedUserSid, AnonymousLogonSid, AliasAdminsSid, AliasUsersSid;
+PSID AliasGuestsSid, AliasPowerUsersSid, AliasAccountOpsSid, AliasSystemOpsSid;
+PSID AliasPrintOpsSid;
+PSID AliasBackupOpsSid;
+
+SID_DATA SidData[12] =
+{
+ { &NullSid, { SECURITY_NULL_SID_AUTHORITY }, SECURITY_NULL_RID },
+ { &WorldSid, { SECURITY_WORLD_SID_AUTHORITY }, SECURITY_WORLD_RID },
+ { &LocalSid, { SECURITY_LOCAL_SID_AUTHORITY }, SECURITY_LOCAL_RID },
+ { &NetworkSid, { SECURITY_NT_AUTHORITY }, SECURITY_NETWORK_RID },
+ { &InteractiveSid, { SECURITY_NT_AUTHORITY }, SECURITY_INTERACTIVE_RID },
+ { &ServiceLogonSid, { SECURITY_NT_AUTHORITY }, SECURITY_SERVICE_RID },
+ { &LocalSystemSid, { SECURITY_NT_AUTHORITY }, SECURITY_LOCAL_SYSTEM_RID },
+ { &LocalServiceSid, { SECURITY_NT_AUTHORITY }, SECURITY_LOCAL_SERVICE_RID },
+ { &NetworkServiceSid, { SECURITY_NT_AUTHORITY }, SECURITY_NETWORK_SERVICE_RID },
+ { &BuiltinDomainSid, { SECURITY_NT_AUTHORITY }, SECURITY_BUILTIN_DOMAIN_RID },
+ { &AuthenticatedUserSid, { SECURITY_NT_AUTHORITY },
SECURITY_AUTHENTICATED_USER_RID },
+ { &AnonymousLogonSid, { SECURITY_NT_AUTHORITY }, SECURITY_ANONYMOUS_LOGON_RID },
+};
+
+DOMAIN_SID_DATA DomainSidData[8] =
+{
+ { &AliasAdminsSid, DOMAIN_ALIAS_RID_ADMINS },
+ { &AliasUsersSid, DOMAIN_ALIAS_RID_USERS },
+ { &AliasGuestsSid, DOMAIN_ALIAS_RID_GUESTS },
+ { &AliasPowerUsersSid, DOMAIN_ALIAS_RID_POWER_USERS },
+ { &AliasAccountOpsSid, DOMAIN_ALIAS_RID_ACCOUNT_OPS },
+ { &AliasSystemOpsSid, DOMAIN_ALIAS_RID_SYSTEM_OPS },
+ { &AliasPrintOpsSid, DOMAIN_ALIAS_RID_PRINT_OPS },
+ { &AliasBackupOpsSid, DOMAIN_ALIAS_RID_BACKUP_OPS },
+};
+
+PSVCHOST_GLOBALS g_pSvchostSharedGlobals;
+DWORD g_SvchostInitFlag;
+HANDLE g_hHeap;
+
+/* FUNCTIONS *****************************************************************/
+
+VOID
+WINAPI
+MemInit (
+ _In_ HANDLE Heap
+ )
+{
+ /* Save the heap handle */
+ g_hHeap = Heap;
+}
+
+BOOL
+WINAPI
+MemFree (
+ _In_ LPVOID lpMem
+ )
+{
+ /* Free memory back into the heap */
+ return HeapFree(g_hHeap, 0, lpMem);
+}
+
+PVOID
+WINAPI
+MemAlloc (
+ _In_ DWORD dwFlags,
+ _In_ DWORD dwBytes
+ )
+{
+ /* Allocate memory from the heap */
+ return HeapAlloc(g_hHeap, dwFlags, dwBytes);
+}
+
+VOID
+WINAPI
+SvchostBuildSharedGlobals (
+ VOID
+ )
+{
+ ASSERT(g_pSvchostSharedGlobals == NULL);
+
+ /* Is RPC initialized? */
+ if (!(g_SvchostInitFlag & SVCHOST_RPC_INIT_COMPLETE))
+ {
+ /* Nope, go initialize it */
+ if (!NT_SUCCESS(RpcpInitRpcServer())) return;
+
+ /* This is now done */
+ g_SvchostInitFlag |= SVCHOST_RPC_INIT_COMPLETE;
+ }
+
+ /* Is NetBIOS initialized? */
+ if (!(g_SvchostInitFlag & SVCHOST_NBT_INIT_COMPLETE))
+ {
+ /* Nope, set it up */
+ SvcNetBiosInit();
+
+ /* This is now done */
+ g_SvchostInitFlag |= SVCHOST_NBT_INIT_COMPLETE;
+ }
+
+ /* Do we have the global SIDs initialized? */
+ if (!(g_SvchostInitFlag & SVCHOST_SID_INIT_COMPLETE))
+ {
+ /* Create the SIDs we'll export in the global structure */
+ if (!NT_SUCCESS(ScCreateWellKnownSids())) return;
+
+ /* This is now done */
+ g_SvchostInitFlag |= SVCHOST_SID_INIT_COMPLETE;
+ }
+
+ /* Allocate memory for the globals */
+ g_pSvchostSharedGlobals = MemAlloc(HEAP_ZERO_MEMORY,
+ sizeof(*g_pSvchostSharedGlobals));
+ if (g_pSvchostSharedGlobals == NULL) return;
+
+ /* Write the pointers to the SIDs */
+ g_pSvchostSharedGlobals->NullSid = NullSid;
+ g_pSvchostSharedGlobals->WorldSid = WorldSid;
+ g_pSvchostSharedGlobals->LocalSid = LocalSid;
+ g_pSvchostSharedGlobals->NetworkSid = NetworkSid;
+ g_pSvchostSharedGlobals->LocalSystemSid = LocalSystemSid;
+ g_pSvchostSharedGlobals->LocalServiceSid = LocalServiceSid;
+ g_pSvchostSharedGlobals->NetworkServiceSid = NetworkServiceSid;
+ g_pSvchostSharedGlobals->BuiltinDomainSid = BuiltinDomainSid;
+ g_pSvchostSharedGlobals->AuthenticatedUserSid = AuthenticatedUserSid;
+ g_pSvchostSharedGlobals->AnonymousLogonSid = AnonymousLogonSid;
+ g_pSvchostSharedGlobals->AliasAdminsSid = AliasAdminsSid;
+ g_pSvchostSharedGlobals->AliasUsersSid = AliasUsersSid;
+ g_pSvchostSharedGlobals->AliasGuestsSid = AliasGuestsSid;
+ g_pSvchostSharedGlobals->AliasPowerUsersSid = AliasPowerUsersSid;
+ g_pSvchostSharedGlobals->AliasAccountOpsSid = AliasAccountOpsSid;
+ g_pSvchostSharedGlobals->AliasSystemOpsSid = AliasSystemOpsSid;
+ g_pSvchostSharedGlobals->AliasPrintOpsSid = AliasPrintOpsSid;
+ g_pSvchostSharedGlobals->AliasBackupOpsSid = AliasBackupOpsSid;
+
+ /* Write the pointers to the callbacks */
+ g_pSvchostSharedGlobals->RpcpStartRpcServer = RpcpStartRpcServer;
+ g_pSvchostSharedGlobals->RpcpStopRpcServer = RpcpStopRpcServer;
+ g_pSvchostSharedGlobals->RpcpStopRpcServerEx = RpcpStopRpcServerEx;
+ g_pSvchostSharedGlobals->SvcNetBiosOpen = SvcNetBiosOpen;
+ g_pSvchostSharedGlobals->SvcNetBiosClose = SvcNetBiosClose;
+ g_pSvchostSharedGlobals->SvcNetBiosReset = SvcNetBiosReset;
+ g_pSvchostSharedGlobals->SvcRegisterStopCallback = SvcRegisterStopCallback;
+}
+
+VOID
+WINAPI
+SvchostCharLowerW (
+ _In_ LPCWSTR lpSrcStr
+ )
+{
+ DWORD cchSrc;
+
+ /* If there's nothing to do, bail out */
+ if (lpSrcStr == NULL) return;
+
+ /* Get the length of the input string */
+ cchSrc = wcslen(lpSrcStr);
+
+ /* Call the locale API to lower-case it */
+ if (LCMapStringW(LANG_USER_DEFAULT,
+ LCMAP_LOWERCASE,
+ lpSrcStr,
+ cchSrc + 1,
+ (LPWSTR)lpSrcStr,
+ cchSrc + 1) == FALSE)
+ {
+ DBG_ERR("SvchostCharLowerW failed for %ws\n", lpSrcStr);
+ }
+}
+
+NTSTATUS
+NTAPI
+ScDomainIdToSid (
+ _In_ PSID SourceSid,
+ _In_ ULONG DomainId,
+ _Out_ PSID *DestinationSid
+ )
+{
+ ULONG sidCount, sidLength;
+ NTSTATUS status;
+
+ /* Get the length of the SID based onthe number of subauthorities */
+ sidCount = *RtlSubAuthorityCountSid(SourceSid);
+ sidLength = RtlLengthRequiredSid(sidCount + 1);
+
+ /* Allocate it */
+ *DestinationSid = RtlAllocateHeap(RtlGetProcessHeap(), 0, sidLength);
+ if (*DestinationSid)
+ {
+ /* Make a copy of it */
+ status = RtlCopySid(sidLength, *DestinationSid, SourceSid);
+ if (NT_SUCCESS(status))
+ {
+ /* Increase the subauthority count */
+ ++*RtlSubAuthorityCountSid(*DestinationSid);
+
+ /* And add the specific domain RID we're creating */
+ *RtlSubAuthoritySid(*DestinationSid, sidCount) = DomainId;
+
+ /* Everything worked */
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ /* The SID copy failed, so free the SID we just allocated */
+ RtlFreeHeap(RtlGetProcessHeap(), 0, *DestinationSid);
+ }
+ }
+ else
+ {
+ /* No space for the SID, bail out */
+ status = STATUS_NO_MEMORY;
+ }
+
+ /* Return back to the caller */
+ return status;
+}
+
+NTSTATUS
+NTAPI
+ScAllocateAndInitializeSid (
+ _Out_ PVOID *Sid,
+ _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
+ _In_ ULONG SubAuthorityCount
+ )
+{
+ NTSTATUS Status;
+
+ /* Allocare toom for the SID */
+ *Sid = RtlAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ RtlLengthRequiredSid(SubAuthorityCount));
+ if (*Sid)
+ {
+ /* Initialize it, we're done */
+ RtlInitializeSid(*Sid, IdentifierAuthority, SubAuthorityCount);
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ /* No memory, we'll fail */
+ Status = STATUS_NO_MEMORY;
+ }
+
+ /* Return what happened */
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+ScCreateWellKnownSids (
+ VOID
+ )
+{
+ ULONG i;
+ NTSTATUS Status;
+
+ /* Loop the non-domain SIDs */
+ for (i = 0; i < RTL_NUMBER_OF(SidData); i++)
+ {
+ /* Convert our optimized structure into an actual SID */
+ Status = ScAllocateAndInitializeSid(&SidData[i].Sid,
+ &SidData[i].Authority,
+ 1);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Write the correct sub-authority */
+ *RtlSubAuthoritySid(SidData[i].Sid, 0) = SidData[i].SubAuthority;
+ }
+
+ /* Now loop the domain SIDs */
+ for (i = 0; i < RTL_NUMBER_OF(DomainSidData); i++)
+ {
+ /* Convert our optimized structure into an actual SID */
+ Status = ScDomainIdToSid(BuiltinDomainSid,
+ DomainSidData[i].SubAuthority,
+ &DomainSidData[i].Sid);
+ if (!NT_SUCCESS(Status)) break;
+ }
+
+ /* If we got to the end, return success */
+ return (i == RTL_NUMBER_OF(DomainSidData)) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
+}
+
Propchange: trunk/reactos/base/services/svchost/globals.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/base/services/svchost/netbios.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/svchost/netb…
==============================================================================
--- trunk/reactos/base/services/svchost/netbios.c (added)
+++ trunk/reactos/base/services/svchost/netbios.c [iso-8859-1] Wed Aug 28 08:32:27 2013
@@ -0,0 +1,158 @@
+/*
+ * PROJECT: ReactOS Service Host
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * FILE: base/services/svchost/netbios.c
+ * PURPOSE: NetBIOS Service Support
+ * PROGRAMMERS: ReactOS Portable Systems Group
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "svchost.h"
+
+/* GLOBALS *******************************************************************/
+
+LONG GlobalNetBiosUseCount;
+DWORD LanaFlags[8];
+CRITICAL_SECTION SvcNetBiosCritSec;
+
+/* FUNCTIONS *****************************************************************/
+
+DWORD
+WINAPI
+SvcNetBiosStatusToApiStatus (
+ _In_ DWORD NetBiosError
+ )
+{
+ /* Convert from one status to another */
+ switch (NetBiosError)
+ {
+ case NRC_GOODRET:
+ return NERR_Success;
+ case NRC_INUSE:
+ case NRC_NAMCONF:
+ return NERR_DuplicateName;
+ case NRC_NOWILD:
+ case NRC_NAMERR:
+ return ERROR_INVALID_PARAMETER;
+ case NRC_NOCALL:
+ return NERR_NameNotFound;
+ case NRC_NORES:
+ return NERR_NoNetworkResource;
+ case NRC_DUPNAME:
+ return NERR_AlreadyExists;
+ case NRC_NAMTFUL:
+ return NERR_TooManyNames;
+ case NRC_ACTSES:
+ return NERR_DeleteLater;
+ case NRC_REMTFUL:
+ return ERROR_REM_NOT_LIST;
+ default:
+ return NERR_NetworkError;
+ }
+}
+
+BOOL
+WINAPI
+LanaFlagIsSet (
+ _In_ UCHAR Lana
+ )
+{
+ DWORD i = Lana / 32;
+
+ /* Clear the flag for this LANA */
+ return (i <= 8) ? LanaFlags[i] & (1 << (Lana - 32 * i)) : FALSE;
+}
+
+VOID
+WINAPI
+SetLanaFlag (
+ _In_ UCHAR Lana
+ )
+{
+ DWORD i = Lana / 32;
+
+ /* Set the flag for this LANA */
+ if (i <= 8) LanaFlags[i] |= 1 << (Lana - 32 * i);
+}
+
+VOID
+WINAPI
+SvcNetBiosInit(
+ VOID
+ )
+{
+ /* Initialize NetBIOS-related structures and variables */
+ InitializeCriticalSection(&SvcNetBiosCritSec);
+ GlobalNetBiosUseCount = 0;
+ ZeroMemory(LanaFlags, sizeof(LanaFlags));
+}
+
+VOID
+WINAPI
+SvcNetBiosClose (
+ VOID
+ )
+{
+ /* While holding the lock, drop a reference*/
+ EnterCriticalSection(&SvcNetBiosCritSec);
+ if ((GlobalNetBiosUseCount != 0) && (--GlobalNetBiosUseCount == 0))
+ {
+ /* All references are gone, clear all LANA's */
+ ZeroMemory(LanaFlags, sizeof(LanaFlags));
+ }
+ LeaveCriticalSection(&SvcNetBiosCritSec);
+}
+
+VOID
+WINAPI
+SvcNetBiosOpen (
+ VOID
+ )
+{
+ /* Increment the reference counter while holding the lock */
+ EnterCriticalSection(&SvcNetBiosCritSec);
+ GlobalNetBiosUseCount++;
+ LeaveCriticalSection(&SvcNetBiosCritSec);
+}
+
+DWORD
+WINAPI
+SvcNetBiosReset (
+ _In_ UCHAR LanaNum
+ )
+{
+ DWORD dwError = ERROR_SUCCESS;
+ UCHAR nbtError;
+ NCB ncb;
+
+ /* Block all other NetBIOS operations */
+ EnterCriticalSection(&SvcNetBiosCritSec);
+
+ /* Is this LANA enabled? */
+ if (!LanaFlagIsSet(LanaNum))
+ {
+ /* Yep, build a reset packet */
+ ZeroMemory(&ncb, sizeof(ncb));
+ ncb.ncb_lsn = 0;
+ ncb.ncb_command = NCBRESET;
+ ncb.ncb_callname[0] = 0xFE; // Max Sessions
+ ncb.ncb_callname[1] = 0;
+ ncb.ncb_callname[2] = 0xFD; // Max Names
+ ncb.ncb_callname[3] = 0;
+ ncb.ncb_lana_num = LanaNum;
+
+ /* Send it */
+ nbtError = Netbios(&ncb);
+
+ /* Convert the status to Win32 format */
+ dwError = SvcNetBiosStatusToApiStatus(nbtError);
+
+ /* Enable the LANA if the reset worked */
+ if (dwError == ERROR_SUCCESS) SetLanaFlag(LanaNum);
+ }
+
+ /* Drop the lock and return */
+ LeaveCriticalSection(&SvcNetBiosCritSec);
+ return dwError;
+}
Propchange: trunk/reactos/base/services/svchost/netbios.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/base/services/svchost/registry.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/svchost/regi…
==============================================================================
--- trunk/reactos/base/services/svchost/registry.c (added)
+++ trunk/reactos/base/services/svchost/registry.c [iso-8859-1] Wed Aug 28 08:32:27 2013
@@ -0,0 +1,201 @@
+/*
+ * PROJECT: ReactOS Service Host
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * FILE: base/services/svchost/registry.c
+ * PURPOSE: Helper functions for accessing the registry
+ * PROGRAMMERS: ReactOS Portable Systems Group
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "svchost.h"
+
+/* FUNCTIONS *****************************************************************/
+
+DWORD
+WINAPI
+RegQueryValueWithAlloc (
+ _In_ HKEY hKey,
+ _In_ LPCWSTR pszValueName,
+ _In_ DWORD dwExpectedType,
+ _Out_ PBYTE* ppbData,
+ _Out_ PDWORD pdwSize
+ )
+{
+ DWORD dwError, dwType, dwBytes;
+ PBYTE pbData;
+ ASSERT(hKey);
+ ASSERT(pszValueName);
+ ASSERT(ppbData);
+ ASSERT(pdwSize);
+
+ /* Assume failure */
+ *ppbData = NULL;
+ *pdwSize = 0;
+
+ /* Query how big and what type the registry data is */
+ dwBytes = 0;
+ dwError = RegQueryValueExW(hKey,
+ pszValueName,
+ NULL,
+ &dwType,
+ NULL,
+ &dwBytes);
+ if (dwError != ERROR_SUCCESS) return dwError;
+
+ /* It if's not the right type, or it's sero bytes, fail*/
+ if ((dwType != dwExpectedType) || (dwBytes == 0)) return ERROR_INVALID_DATA;
+
+ /* Allocate space to hold the data */
+ pbData = MemAlloc(0, dwBytes);
+ if (pbData == NULL) return ERROR_OUTOFMEMORY;
+
+ /* Now get the real registry data */
+ dwError = RegQueryValueExW(hKey,
+ pszValueName,
+ NULL,
+ &dwType,
+ pbData,
+ &dwBytes);
+ if (dwError != ERROR_SUCCESS)
+ {
+ /* We failed, free the data since it won't be needed */
+ MemFree(pbData);
+ }
+ else
+ {
+ /* It worked, return the data and size back to the caller */
+ *ppbData = pbData;
+ *pdwSize = dwBytes;
+ }
+
+ /* All done */
+ return dwError;
+}
+
+DWORD
+WINAPI
+RegQueryDword (
+ _In_ HKEY hKey,
+ _In_ LPCWSTR pszValueName,
+ _Out_ PDWORD pdwValue
+ )
+{
+ DWORD dwError, cbData, dwType;
+ ASSERT(hKey);
+ ASSERT(pszValueName);
+ ASSERT(pdwValue);
+
+ /* Attempt to read 4 bytes */
+ cbData = sizeof(DWORD);
+ dwError = RegQueryValueExW(hKey, pszValueName, 0, &dwType, 0, &cbData);
+
+ /* If we didn't get back a DWORD... */
+ if ((dwError == ERROR_SUCCESS) && (dwType != REG_DWORD))
+ {
+ /* Zero out the output and fail */
+ *pdwValue = 0;
+ dwError = ERROR_INVALID_DATATYPE;
+ }
+
+ /* All done! */
+ return dwError;
+}
+
+DWORD
+WINAPI
+RegQueryString (
+ _In_ HKEY hKey,
+ _In_ LPCWSTR pszValueName,
+ _In_ DWORD dwExpectedType,
+ _Out_ PBYTE* ppbData
+ )
+{
+ DWORD dwSize;
+ ASSERT(hKey);
+ ASSERT(pszValueName);
+
+ /* Call the helper function */
+ return RegQueryValueWithAlloc(hKey,
+ pszValueName,
+ dwExpectedType,
+ ppbData,
+ &dwSize);
+}
+
+DWORD
+WINAPI
+RegQueryStringA (
+ _In_ HKEY hKey,
+ _In_ LPCWSTR pszValueName,
+ _In_ DWORD dwExpectedType,
+ _Out_ LPCSTR* ppszData
+ )
+{
+ DWORD dwError;
+ LPWSTR pbLocalData;
+ DWORD cchValueName, cbMultiByte;
+ LPSTR pszData;
+ ASSERT(hKey);
+ ASSERT(pszValueName);
+ ASSERT(ppszData);
+
+ /* Assume failure */
+ *ppszData = NULL;
+
+ /* Query the string in Unicode first */
+ dwError = RegQueryString(hKey,
+ pszValueName,
+ dwExpectedType,
+ (PBYTE*)&pbLocalData);
+ if (dwError != ERROR_SUCCESS) return dwError;
+
+ /* Get the length of the Unicode string */
+ cchValueName = lstrlenW(pbLocalData);
+
+ /* See how much space it would take to convert to ANSI */
+ cbMultiByte = WideCharToMultiByte(CP_ACP,
+ 0,
+ pbLocalData,
+ cchValueName + 1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (cbMultiByte != 0)
+ {
+ /* Allocate the space, assuming failure */
+ dwError = ERROR_OUTOFMEMORY;
+ pszData = MemAlloc(0, cbMultiByte);
+ if (pszData != NULL)
+ {
+ /* What do you know, it worked! */
+ dwError = ERROR_SUCCESS;
+
+ /* Now do the real conversion */
+ if (WideCharToMultiByte(CP_ACP,
+ 0,
+ pbLocalData,
+ cchValueName + 1,
+ pszData,
+ cbMultiByte,
+ NULL,
+ NULL) != 0)
+ {
+ /* It worked, return the data back to the caller */
+ *ppszData = pszData;
+ }
+ else
+ {
+ /* It failed, free our buffer and get the error code */
+ MemFree(pszData);
+ dwError = GetLastError();
+ }
+ }
+ }
+
+ /* Free the original Unicode string and return the error */
+ MemFree(pbLocalData);
+ return dwError;
+}
+
Propchange: trunk/reactos/base/services/svchost/registry.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/base/services/svchost/rpcsrv.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/svchost/rpcs…
==============================================================================
--- trunk/reactos/base/services/svchost/rpcsrv.c (added)
+++ trunk/reactos/base/services/svchost/rpcsrv.c [iso-8859-1] Wed Aug 28 08:32:27 2013
@@ -0,0 +1,156 @@
+/*
+ * PROJECT: ReactOS Service Host
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * FILE: base/services/svchost/rpcsrv.c
+ * PURPOSE: RPC Service Support
+ * PROGRAMMERS: ReactOS Portable Systems Group
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "svchost.h"
+
+/* GLOBALS *******************************************************************/
+
+LONG RpcpNumInstances;
+CRITICAL_SECTION RpcpCriticalSection;
+
+/* FUNCTIONS *****************************************************************/
+
+NTSTATUS
+NTAPI
+RpcpInitRpcServer (
+ VOID
+ )
+{
+ /* Clear the reference count and initialize the critical section */
+ RpcpNumInstances = 0;
+ return RtlInitializeCriticalSection((PVOID)&RpcpCriticalSection);
+}
+
+NTSTATUS
+NTAPI
+RpcpStopRpcServer (
+ _In_ RPC_IF_HANDLE IfSpec
+ )
+{
+ RPC_STATUS rpcStatus;
+
+ /* Unregister the interface */
+ rpcStatus = RpcServerUnregisterIf(IfSpec, NULL, TRUE);
+
+ /* Acquire the lock while we dereference the RPC services */
+ EnterCriticalSection(&RpcpCriticalSection);
+ if (--RpcpNumInstances == 0)
+ {
+ /* All RPC services stopped, rundown the server */
+ RpcMgmtStopServerListening(NULL);
+ RpcMgmtWaitServerListen();
+ }
+
+ /* Release the lock and return the unregister result */
+ LeaveCriticalSection(&RpcpCriticalSection);
+ return I_RpcMapWin32Status(rpcStatus);
+}
+
+NTSTATUS
+NTAPI
+RpcpStopRpcServerEx (
+ _In_ RPC_IF_HANDLE IfSpec
+ )
+{
+ RPC_STATUS rpcStatus;
+
+ /* Unregister the interface */
+ rpcStatus = RpcServerUnregisterIfEx(IfSpec, NULL, TRUE);
+
+ /* Acquire the lock while we dereference the RPC services */
+ EnterCriticalSection(&RpcpCriticalSection);
+ if (--RpcpNumInstances == 0)
+ {
+ /* All RPC services stopped, rundown the server */
+ RpcMgmtStopServerListening(NULL);
+ RpcMgmtWaitServerListen();
+ }
+
+ /* Release the lock and return the unregister result */
+ LeaveCriticalSection(&RpcpCriticalSection);
+ return I_RpcMapWin32Status(rpcStatus);
+}
+
+NTSTATUS
+NTAPI
+RpcpAddInterface (
+ _In_ LPCWSTR IfName,
+ _In_ RPC_IF_HANDLE IfSpec
+ )
+{
+ PWCHAR endpointName;
+ NTSTATUS ntStatus;
+ RPC_STATUS rpcStatus;
+
+ /* Allocate space for the interface name and the \\PIPE\\ prefix */
+ endpointName = LocalAlloc(0, sizeof(WCHAR) * wcslen(IfName) + 16);
+ if (endpointName)
+ {
+ /* Copy the prefix, and then the interface name */
+ wcscpy(endpointName, L"\\PIPE\\");
+ wcscat(endpointName, IfName);
+
+ /* Create a named pipe endpoint with this name */
+ rpcStatus = RpcServerUseProtseqEpW(L"ncacn_np", 10, endpointName,
NULL);
+ if ((rpcStatus != RPC_S_OK) && (rpcStatus != RPC_S_DUPLICATE_ENDPOINT))
+ {
+ /* We couldn't create it, or it already existed... */
+ DbgPrint("RpcServerUseProtseqW failed! rpcstatus = %u\n",
rpcStatus);
+ }
+ else
+ {
+ /* It worked, register an interface on this endpoint now*/
+ rpcStatus = RpcServerRegisterIf(IfSpec, 0, 0);
+ }
+
+ /* In both success and failure, free the name, and convert the status */
+ LocalFree(endpointName);
+ ntStatus = I_RpcMapWin32Status(rpcStatus);
+ }
+ else
+ {
+ /* No memory, bail out */
+ ntStatus = STATUS_NO_MEMORY;
+ }
+
+ /* Return back to the caller */
+ return ntStatus;
+}
+
+NTSTATUS
+NTAPI
+RpcpStartRpcServer (
+ _In_ LPCWSTR IfName,
+ _In_ RPC_IF_HANDLE IfSpec
+ )
+{
+ NTSTATUS ntStatus;
+
+ /* Acquire the lock while we instantiate a new interface */
+ EnterCriticalSection(&RpcpCriticalSection);
+
+ /* Add this interface to the service */
+ ntStatus = RpcpAddInterface(IfName, IfSpec);
+ if (!ntStatus)
+ {
+ /* Increment the reference count to see if this was the first interface */
+ if (++RpcpNumInstances == 1)
+ {
+ /* It was, so put the server into listening mode now */
+ ntStatus = RpcServerListen(1, 12345, TRUE);
+ if (ntStatus == RPC_S_ALREADY_LISTENING) ntStatus = STATUS_SUCCESS;
+ }
+ }
+
+ /* Release the lock and return back the result to the caller */
+ LeaveCriticalSection(&RpcpCriticalSection);
+ return I_RpcMapWin32Status(ntStatus);
+}
+
Propchange: trunk/reactos/base/services/svchost/rpcsrv.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/base/services/svchost/security.cxx
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/svchost/secu…
==============================================================================
--- trunk/reactos/base/services/svchost/security.cxx (added)
+++ trunk/reactos/base/services/svchost/security.cxx [iso-8859-1] Wed Aug 28 08:32:27
2013
@@ -0,0 +1,227 @@
+/*
+ * PROJECT: ReactOS Service Host
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * FILE: base/services/svchost/security.c
+ * PURPOSE: Initializes the COM Object Security Model and Parameters
+ * PROGRAMMERS: ReactOS Portable Systems Group
+ */
+
+/* INCLUDES ******************************************************************/
+
+#define __callback
+extern "C"
+{
+#include "svchost.h"
+}
+
+/* GLOBALS *******************************************************************/
+
+SID NtSid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID }
};
+
+/* FUNCTIONS *****************************************************************/
+
+DWORD
+WINAPI
+DwInitializeSdFromThreadToken (
+ _Out_ PVOID *ppSecurityDescriptor,
+ _Out_ PACL *ppAcl
+ )
+{
+ HANDLE hToken;
+ DWORD dwGroupLength, dwUserLength, dwError, dwAlignLength;
+ PTOKEN_PRIMARY_GROUP pTokenGroup;
+ PTOKEN_USER pTokenUser;
+ EXPLICIT_ACCESS_W pListOfExplicitEntries;
+ PACL pAcl = NULL;
+ PISECURITY_DESCRIPTOR pSd;
+
+ /* Assume failure */
+ *ppSecurityDescriptor = NULL;
+ *ppAcl = NULL;
+
+ /* Open the token of the current thread */
+ if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, 0, &hToken) == FALSE)
+ {
+ /* The thread is not impersonating, use the process token */
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) == FALSE)
+ {
+ /* No token could be queried, fail */
+ return GetLastError();
+ }
+ }
+
+ /* Get the size of the token's user */
+ if ((GetTokenInformation(hToken, TokenUser, NULL, 0, &dwUserLength) == FALSE) ||
+ (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
+ {
+ return GetLastError();
+ }
+
+ /* Get the size of the token's primary group */
+ if ((GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &dwGroupLength) ==
FALSE) ||
+ (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
+ {
+ return GetLastError();
+ }
+
+ /* Allocate an SD large enough to hold the SIDs for the above */
+ dwAlignLength = ALIGN_UP(dwUserLength, ULONG);
+ pSd = (PISECURITY_DESCRIPTOR)MemAlloc(0,
+ dwAlignLength +
+ dwGroupLength +
+ sizeof(*pSd));
+ if (pSd == NULL) return ERROR_OUTOFMEMORY;
+
+ /* Assume success for now */
+ dwError = ERROR_SUCCESS;
+
+ /* We'll put them right after the SD itself */
+ pTokenUser = (PTOKEN_USER)(pSd + 1);
+ pTokenGroup = (PTOKEN_PRIMARY_GROUP)((ULONG_PTR)pTokenUser + dwAlignLength);
+
+ /* Now initialize it */
+ if (InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION) == FALSE)
+ {
+ dwError = GetLastError();
+ }
+
+ /* And do the actual query for the user */
+ if (GetTokenInformation(hToken,
+ TokenUser,
+ pTokenUser,
+ dwUserLength,
+ &dwUserLength) == FALSE)
+ {
+ dwError = GetLastError();
+ }
+
+ /* And then the actual query for the primary group */
+ if (GetTokenInformation(hToken,
+ TokenPrimaryGroup,
+ pTokenGroup,
+ dwGroupLength,
+ &dwGroupLength) == FALSE)
+ {
+ dwError = GetLastError();
+ }
+
+ /* Set the user as owner */
+ if (SetSecurityDescriptorOwner(pSd, pTokenUser->User.Sid, FALSE) == FALSE)
+ {
+ dwError = GetLastError();
+ }
+
+ /* Set the group as primary */
+ if (SetSecurityDescriptorGroup(pSd, pTokenGroup->PrimaryGroup, FALSE) == FALSE)
+ {
+ dwError = GetLastError();
+ }
+
+ /* Did everything so far work out? */
+ if (dwError == ERROR_SUCCESS)
+ {
+ /* Yes, create an ACL granting the SYSTEM account access */
+ pListOfExplicitEntries.grfAccessMode = SET_ACCESS;
+ pListOfExplicitEntries.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
+ pListOfExplicitEntries.grfAccessPermissions = 1;
+ pListOfExplicitEntries.grfInheritance = 0;
+ pListOfExplicitEntries.Trustee.pMultipleTrustee = 0;
+ pListOfExplicitEntries.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+ pListOfExplicitEntries.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ pListOfExplicitEntries.Trustee.ptstrName = (LPWSTR)&NtSid;
+ dwError = SetEntriesInAclW(1, &pListOfExplicitEntries, NULL, &pAcl);
+ if (dwError == ERROR_SUCCESS)
+ {
+ /* Make that ACL the DACL of the SD we just built */
+ if (SetSecurityDescriptorDacl(pSd, 1, pAcl, FALSE) == FALSE)
+ {
+ /* We failed, bail out */
+ LocalFree(pAcl);
+ dwError = GetLastError();
+ }
+ else
+ {
+ /* Now we have the SD and the ACL all ready to go */
+ *ppSecurityDescriptor = pSd;
+ *ppAcl = pAcl;
+ return ERROR_SUCCESS;
+ }
+ }
+ }
+
+ /* Failure path, we'll free the SD since the caller can't use it */
+ MemFree(pSd);
+ return dwError;
+}
+
+BOOL
+WINAPI
+InitializeSecurity (
+ _In_ DWORD dwParam,
+ _In_ DWORD dwAuthnLevel,
+ _In_ DWORD dwImpLevel,
+ _In_ DWORD dwCapabilities
+ )
+{
+ HRESULT hr;
+ PACL pAcl;
+ PSECURITY_DESCRIPTOR pSecurityDescriptor;
+ IGlobalOptions *pGlobalOptions;
+ ASSERT(dwParam != 0);
+
+ /* Create a valid SD and ACL based on the current thread's token */
+ if (DwInitializeSdFromThreadToken(&pSecurityDescriptor, &pAcl) ==
ERROR_SUCCESS)
+ {
+ /* It worked -- initialize COM without DDE support */
+ hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
+ }
+ else
+ {
+ /* Don't keep going if we don't have an SD */
+ hr = E_FAIL;
+ }
+
+ /* Did we make it? */
+ if (SUCCEEDED(hr))
+ {
+ /* Indeed, initialize COM security now */
+ DBG_TRACE("Calling CoInitializeSecurity (dwAuthCapabilities =
0x%08x)\n",
+ dwCapabilities);
+ hr = CoInitializeSecurity(pSecurityDescriptor,
+ -1,
+ NULL,
+ NULL,
+ dwAuthnLevel,
+ dwImpLevel,
+ NULL,
+ dwCapabilities,
+ NULL);
+ if (FAILED(hr)) DBG_ERR("CoInitializeSecurity returned hr=0x%08x\n",
hr);
+ }
+
+ /* Free the SD and ACL since we no longer need it */
+ MemFree(pSecurityDescriptor);
+ LocalFree(pAcl);
+
+ /* Did we initialize COM correctly? */
+ if (SUCCEEDED(hr))
+ {
+ /* Get the COM Global Options Interface */
+ hr = CoCreateInstance(CLSID_GlobalOptions,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IGlobalOptions,
+ (LPVOID*)&pGlobalOptions);
+ if (SUCCEEDED(hr))
+ {
+ /* Use it to disable COM exception handling */
+ hr = pGlobalOptions->Set(COMGLB_EXCEPTION_HANDLING,
+ COMGLB_EXCEPTION_DONOT_HANDLE);
+ pGlobalOptions->Release();
+ ASSERT(SUCCEEDED(hr));
+ }
+ }
+
+ /* Return whether all COM calls were successful or not */
+ return SUCCEEDED(hr);
+}
Propchange: trunk/reactos/base/services/svchost/security.cxx
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/base/services/svchost/svchost.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/svchost/svch…
==============================================================================
--- trunk/reactos/base/services/svchost/svchost.c [iso-8859-1] (original)
+++ trunk/reactos/base/services/svchost/svchost.c [iso-8859-1] Wed Aug 28 08:32:27 2013
@@ -1,305 +1,1298 @@
/*
- * PROJECT: ReactOS SvcHost
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: /base/services/svchost/svchost.c
- * PURPOSE: Provide dll service loader
- * PROGRAMMERS: Gregor Brunmar (gregor.brunmar(a)home.se)
+ * PROJECT: ReactOS Service Host
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * FILE: base/services/svchost/svchost.c
+ * PURPOSE: Main Service Host Implementation Routines
+ * PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES ******************************************************************/
#include "svchost.h"
-#define NDEBUG
-#include <debug.h>
-
-/* DEFINES *******************************************************************/
-
-static PCWSTR SVCHOST_REG_KEY = L"SOFTWARE\\Microsoft\\Windows
NT\\CurrentVersion\\SvcHost";
-static PCWSTR SERVICE_KEY = L"SYSTEM\\CurrentControlSet\\Services\\";
-static PCWSTR PARAMETERS_KEY = L"\\Parameters";
-
-#define REG_MAX_DATA_SIZE 2048
-
-static PSERVICE FirstService = NULL;
+/* GLOBALS *******************************************************************/
+
+LIST_ENTRY DllList;
+CRITICAL_SECTION ListLock;
+DWORD ServiceCount;
+LPCWSTR ServiceNames;
+PSVCHOST_SERVICE ServiceArray;
/* FUNCTIONS *****************************************************************/
-BOOL PrepareService(PCWSTR ServiceName)
-{
- HKEY hServiceKey;
- WCHAR ServiceKeyBuffer[512];
- HRESULT Result;
- DWORD ValueType;
- PWSTR Buffer;
- DWORD BufferSize;
- LONG RetVal;
- HINSTANCE hServiceDll;
- PWSTR DllPath;
- DWORD DllPathSize;
- LPSERVICE_MAIN_FUNCTION ServiceMainFunc;
- PSERVICE Service;
- DWORD ServiceNameSize;
-
- /* Compose the registry path to the service's "Parameter" key */
- Result = StringCbCopy(ServiceKeyBuffer, sizeof(ServiceKeyBuffer), SERVICE_KEY);
- if (FAILED(Result))
- {
- DPRINT1("Buffer overflow for service name: '%ls'\n",
ServiceName);
- return FALSE;
- }
- Result = StringCbCat(ServiceKeyBuffer, sizeof(ServiceKeyBuffer), ServiceName);
- if (FAILED(Result))
- {
- DPRINT1("Buffer overflow for service name: '%ls'\n",
ServiceName);
- return FALSE;
- }
- Result = StringCbCat(ServiceKeyBuffer, sizeof(ServiceKeyBuffer), PARAMETERS_KEY);
- if (FAILED(Result))
- {
- DPRINT1("Buffer overflow for service name: '%ls'\n",
ServiceName);
- return FALSE;
- }
-
- /* Open the service registry key to find the dll name */
- RetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ServiceKeyBuffer, 0, KEY_READ,
&hServiceKey);
- if (RetVal != ERROR_SUCCESS)
- {
- DPRINT1("Could not open service key (%ls)\n", ServiceKeyBuffer);
- return FALSE;
- }
-
- BufferSize = 0;
- RetVal = RegQueryValueEx(hServiceKey, L"ServiceDll", NULL, &ValueType,
NULL, &BufferSize);
- if (RetVal != ERROR_SUCCESS)
- {
- RegCloseKey(hServiceKey);
- return FALSE;
- }
-
- Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
- if (Buffer == NULL)
- {
- DPRINT1("Not enough memory for service: %ls\n", ServiceName);
- RegCloseKey(hServiceKey);
- return FALSE;
- }
-
- RetVal = RegQueryValueEx(hServiceKey, L"ServiceDll", NULL, &ValueType,
(LPBYTE)Buffer, &BufferSize);
- if (RetVal != ERROR_SUCCESS || BufferSize == 0)
- {
- DPRINT1("Could not read 'ServiceDll' value from service: %ls,
ErrorCode: 0x%lx\n", ServiceName, RetVal);
- RegCloseKey(hServiceKey);
- HeapFree(GetProcessHeap(), 0, Buffer);
- return FALSE;
- }
- RegCloseKey(hServiceKey);
-
- if (ValueType == REG_EXPAND_SZ)
- {
- /* Convert possible %SystemRoot% to a real path */
- DllPathSize = ExpandEnvironmentStrings(Buffer, NULL, 0);
- if (DllPathSize == 0)
- {
- DPRINT1("Invalid ServiceDll path: %ls, ErrorCode: %lu\n", Buffer,
GetLastError());
- HeapFree(GetProcessHeap(), 0, Buffer);
- return FALSE;
- }
- DllPath = HeapAlloc(GetProcessHeap(), 0, DllPathSize * sizeof(WCHAR));
- if (DllPath == NULL)
- {
- DPRINT1("Not enough memory for service: %ls\n", ServiceName);
- HeapFree(GetProcessHeap(), 0, Buffer);
- return FALSE;
- }
- if (ExpandEnvironmentStrings(Buffer, DllPath, DllPathSize) != DllPathSize)
- {
- DPRINT1("Invalid ServiceDll path: %ls, ErrorCode: %lu\n", Buffer,
GetLastError());
- HeapFree(GetProcessHeap(), 0, DllPath);
- HeapFree(GetProcessHeap(), 0, Buffer);
- return FALSE;
- }
-
- HeapFree(GetProcessHeap(), 0, Buffer);
- }
- else if (ValueType == REG_SZ)
- {
- DllPath = Buffer;
+__callback
+LONG
+WINAPI
+SvchostUnhandledExceptionFilter (
+ _In_ struct _EXCEPTION_POINTERS * ExceptionInfo
+ )
+{
+ /* Call the default OS handler */
+ return RtlUnhandledExceptionFilter(ExceptionInfo);
+}
+
+VOID
+WINAPI
+DummySvchostCtrlHandler (
+ _In_ DWORD dwControl
+ )
+{
+ /* This is just a stub while we abort loading */
+ return;
+}
+
+PSVCHOST_OPTIONS
+WINAPI
+BuildCommandOptions (
+ _In_ LPWSTR pszCmdLine
+ )
+{
+ ULONG cbCmdLine;
+ PSVCHOST_OPTIONS pOptions;
+ LPWSTR pch, pGroupNameStart, lpServiceGroup;
+ LPWSTR *pGroupName = NULL;
+
+ /* Nothing to do without a command-line */
+ if (pszCmdLine == NULL) return ERROR_SUCCESS;
+
+ /* Get the length if the command line*/
+ cbCmdLine = sizeof(WCHAR) * lstrlenW(pszCmdLine) + sizeof(UNICODE_NULL);
+
+ /* Allocate a buffer for the parsed options */
+ pOptions = MemAlloc(HEAP_ZERO_MEMORY, cbCmdLine + sizeof(*pOptions));
+ if (pOptions == NULL) return ERROR_SUCCESS;
+
+ /* Copy the buffer into the parsed options block */
+ pOptions->CmdLineBuffer = (PWCHAR)(pOptions + 1);
+ memcpy(pOptions->CmdLineBuffer, pszCmdLine, cbCmdLine);
+
+ /* Set the command-line as being inside the block itself */
+ pch = pOptions->CmdLineBuffer;
+ ASSERT(pch);
+ pOptions->CmdLine = pch;
+
+ /* Now scan it */
+ while (*pch != UNICODE_NULL)
+ {
+ /* And look for the first space or TAB */
+ if ((*pch == ' ') || (*pch == '\t'))
+ {
+ /* Terminate the command-line there */
+ *pch++ = UNICODE_NULL;
+ break;
+ }
+
+ /* Keep searching */
+ pch++;
+ }
+
+ /* Lowercase the entire command line, but not the options */
+ SvchostCharLowerW(pOptions->CmdLine);
+
+ /* Loop over the command-line */
+ while (*pch != UNICODE_NULL)
+ {
+ /* Do an inner loop within it */
+ while (*pch != UNICODE_NULL)
+ {
+ /* And keep going until we find a space or TAB */
+ if ((*pch != ' ') && (*pch != '\t')) break;
+ pch++;
+ }
+
+ /* Did we reach the end? If so, bail out */
+ if (*pch == UNICODE_NULL) break;
+
+ /* We found the space -- is it followed by a dash or slash? */
+ if ((*pch == '-' || *pch == '/') && (*(pch + 1) !=
UNICODE_NULL))
+ {
+ /* Yep, and there's at least one character. Is it k or K? */
+ pch++;
+ if (*pch == 'k' || *pch == 'K')
+ {
+ /* Yep, we have a proper command line with a group! */
+ pOptions->HasServiceGroup = TRUE;
+ pGroupName = &pOptions->ServiceGroupName;
+ }
+
+ /* Keep going -- the name follows between spaces or quotes */
+ pch++;
+ }
+ else
+ {
+ /* Nope, so this might be the group being entered */
+ pGroupNameStart = pch;
+
+ /* Check if there's a quote */
+ if ((*pch == '"') && (*(pch + 1) != UNICODE_NULL))
+ {
+ /* There is, keep going until the quote is over with */
+ pGroupNameStart = ++pch;
+ while (*pch) if (*pch++ == '"') break;
+ }
+ else
+ {
+ /* No quote, so keep going until the next space or TAB */
+ while ((*pch) && ((*pch != ' ') && (*pch !=
'\t'))) pch++;
+ }
+
+ /* Now we have a space or quote deliminated name, terminate it */
+ if (*pch) *pch++ = UNICODE_NULL;
+
+ /* Ok, so we have a string -- was it preceeded by a -K or /K? */
+ if (pGroupName)
+ {
+ /* Yes it was, remember this, and don't overwrite it later */
+ *pGroupName = pGroupNameStart;
+ pGroupName = NULL;
+ }
+ }
+ }
+
+ /* Print out the service group for the debugger, and the command line */
+ DBG_TRACE("Command line : %ws\n", pszCmdLine);
+ lpServiceGroup = (pOptions->HasServiceGroup) ?
+ pOptions->ServiceGroupName : L"No";
+ DBG_TRACE("Service Group : %ws\n", lpServiceGroup);
+
+ /* Was a group specified? */
+ if (pOptions->HasServiceGroup == FALSE)
+ {
+ /* This isn't valid. Print out help on the debugger and fail */
+ DBG_TRACE("Generic Service Host\n\n"
+ "%ws [-k <key>] | [-r] | <service>\n\n"
+ " -k <key> Host all services whose ImagePath
matches\n"
+ " %ws -k <key>.\n\n",
+ lpServiceGroup);
+ MemFree(pOptions);
+ pOptions = NULL;
+ }
+
+ /* Return the allocated option block, if valid*/
+ return pOptions;
+}
+
+DWORD
+WINAPI
+ReadPerInstanceRegistryParameters (
+ _In_ HKEY hKey,
+ _In_ PSVCHOST_OPTIONS pOptions
+ )
+{
+ DWORD dwError, dwData;
+ HKEY hSubKey;
+
+ /* We should have a name for this service group... */
+ ASSERT(pOptions->ServiceGroupName);
+
+ /* Query the group to see what services are part of it */
+ dwError = RegQueryString(hKey,
+ pOptions->ServiceGroupName,
+ REG_MULTI_SZ,
+ (PBYTE*)&ServiceNames);
+ if ((dwError == ERROR_SUCCESS) &&
+ ((ServiceNames == NULL) || (*ServiceNames == UNICODE_NULL)))
+ {
+ /* If the key exists but there's no data, fail */
+ return ERROR_INVALID_DATA;
+ }
+
+ /* Open the key for this group */
+ if (RegOpenKeyExW(hKey,
+ pOptions->ServiceGroupName,
+ 0,
+ KEY_READ,
+ &hSubKey) != ERROR_SUCCESS)
+ {
+ /* If we couldn't, bail out */
+ return dwError;
+ }
+
+ /* Check if we should initialize COM */
+ if (RegQueryDword(hSubKey,
+ L"CoInitializeSecurityParam",
+ &dwData) == ERROR_SUCCESS)
+ {
+ /* Yes, remember the parameter to be sent when we do so */
+ pOptions->CoInitializeSecurityParam = dwData;
+ }
+
+ /* Also, if COM is requested, we must read a bunch more data... */
+ if (pOptions->CoInitializeSecurityParam)
+ {
+ /* First, read the authentication level, use a default if none is set */
+ if (RegQueryDword(hSubKey, L"AuthenticationLevel", &dwData))
+ {
+ pOptions->AuthenticationLevel = RPC_C_AUTHN_LEVEL_PKT;
+ }
+ else
+ {
+ pOptions->AuthenticationLevel = dwData;
+ }
+
+ /* Do the same for the impersonation level */
+ if (RegQueryDword(hSubKey, L"ImpersonationLevel", &dwData))
+ {
+ pOptions->ImpersonationLevel = RPC_C_IMP_LEVEL_IDENTIFY;
+ }
+ else
+ {
+ pOptions->ImpersonationLevel = dwData;
+ }
+
+ /* Do the same for the authentication capabilities */
+ if (RegQueryDword(hSubKey, L"AuthenticationCapabilities",
&dwData))
+ {
+ pOptions->AuthenticationCapabilities = EOAC_NO_CUSTOM_MARSHAL |
+ EOAC_DISABLE_AAA;
+ }
+ else
+ {
+ pOptions->AuthenticationCapabilities = dwData;
+ }
+ }
+
+ /* Check if we need a specific RPC stack size, if not, we'll set it later */
+ if (!RegQueryDword(hSubKey, L"DefaultRpcStackSize", &dwData))
+ {
+ pOptions->DefaultRpcStackSize = dwData;
+ }
+
+ /* Finally, check if the services should be marked critical later on */
+ if (!RegQueryDword(hSubKey, L"SystemCritical", &dwData))
+ {
+ pOptions->SystemCritical = dwData;
+ }
+
+ /* All done reading the settings */
+ RegCloseKey(hSubKey);
+ return dwError;
+}
+
+VOID
+WINAPI
+BuildServiceArray (
+ _In_ PSVCHOST_OPTIONS lpOptions
+ )
+{
+ DWORD dwError;
+ PSVCHOST_SERVICE pService;
+ LPCWSTR pszServiceName;
+ HKEY hKey;
+
+ /* Open the service host key */
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"Software\\Microsoft\\Windows
NT\\CurrentVersion\\Svchost",
+ 0,
+ KEY_READ,
+ &hKey);
+ if (dwError != ERROR_SUCCESS) return;
+
+ /* Read all the parameters for this service group */
+ dwError = ReadPerInstanceRegistryParameters(hKey, lpOptions);
+ RegCloseKey(hKey);
+ if (dwError != ERROR_SUCCESS) return;
+
+ /* Acquire the database lock while we create the service group */
+ EnterCriticalSection(&ListLock);
+
+ /* Loop the array of services for this group */
+ pszServiceName = ServiceNames;
+ while (*pszServiceName != UNICODE_NULL)
+ {
+ /* For each one, increment the amount of services we'llhost */
+ ServiceCount++;
+ pszServiceName += lstrlenW(pszServiceName) + 1;
+ }
+
+ /* We should host at least one... */
+ ASSERT(ServiceCount);
+
+ /* Now allocate an array to hold all their pointers */
+ ServiceArray = MemAlloc(HEAP_ZERO_MEMORY, sizeof(*pService) * ServiceCount);
+ if (ServiceArray)
+ {
+ /* Start at the beginning of the array */
+ pService = ServiceArray;
+
+ /* Loop through all the services */
+ pszServiceName = ServiceNames;
+ while (*pszServiceName != UNICODE_NULL)
+ {
+ /* Save the service's name and move to the next entry */
+ pService++->pszServiceName = pszServiceName;
+ pszServiceName += lstrlenW(pszServiceName) + 1;
+ }
+
+ /* We should have gotten the same count as earlier! */
+ ASSERT(pService == ServiceArray + ServiceCount);
+ }
+
+ /* We're done, drop the lock */
+ LeaveCriticalSection(&ListLock);
+}
+
+BOOL
+WINAPI
+FDebugBreakForService (
+ _In_ LPCWSTR ServiceName
+ )
+{
+ DWORD Data;
+ BOOL DebugBreakOn = FALSE;
+ HKEY hKey, hSubKey;
+
+ /* Open the key for Svchost itself */
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"Software\\Microsoft\\Windows
NT\\CurrentVersion\\Svchost",
+ 0,
+ KEY_READ,
+ &hKey) == ERROR_SUCCESS)
+ {
+ /* That worked, now open the key for this service, if it exists */
+ if (RegOpenKeyExW(hKey, ServiceName, 0, KEY_READ, &hSubKey) ==
ERROR_SUCCESS)
+ {
+ /* It does -- is there a DebugBreak value set? */
+ if (RegQueryDword(hSubKey, L"DebugBreak", &Data) ==
ERROR_SUCCESS)
+ {
+ /* There is! Check if it's 0 or 1 */
+ DebugBreakOn = Data != 0;
+ }
+
+ /* Done, close the service key */
+ RegCloseKey(hSubKey);
+ }
+
+ /* Done, close the svchost key */
+ RegCloseKey(hKey);
+ }
+
+ /* Return if the value was set or not */
+ return DebugBreakOn;
+}
+
+DWORD
+WINAPI
+OpenServiceParametersKey (
+ _In_ LPCWSTR lpSubKey,
+ _Out_ PHKEY phKey
+ )
+{
+ DWORD dwError;
+ HKEY hSubKey = NULL, hKey = NULL;
+ ASSERT(phKey);
+
+ /* Open the services key */
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"System\\CurrentControlSet\\Services",
+ 0,
+ KEY_READ,
+ &hKey);
+ if (dwError == ERROR_SUCCESS)
+ {
+ /* Now open the service specific key, returning its handle */
+ dwError = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, &hSubKey);
+ if (dwError == ERROR_SUCCESS)
+ {
+ /* And if that worked, return a handle to the parameters key */
+ dwError = RegOpenKeyExW(hSubKey,
+ L"Parameters",
+ 0,
+ KEY_READ,
+ phKey);
+ }
+ }
+
+ /* Clean up any leftovers*/
+ if (hKey != NULL) RegCloseKey(hKey);
+ if (hSubKey != NULL) RegCloseKey(hSubKey);
+ return dwError;
+}
+
+VOID
+WINAPI
+UnloadServiceDll (
+ _In_ PSVCHOST_SERVICE pService
+ )
+{
+ DWORD cbData;
+ DWORD Data;
+ DWORD dwType;
+ HKEY hKey = NULL;
+
+ cbData = 4;
+ Data = 0;
+
+ /* Grab the lock while we touch the thread count and potentially unload */
+ EnterCriticalSection(&ListLock);
+
+ /* There is one less active callout into the DLL, it may be unloadabl now */
+ ASSERT(pService->cServiceActiveThreadCount > 0);
+ pService->cServiceActiveThreadCount--;
+
+ /* Try to open the service registry key */
+ if (OpenServiceParametersKey(pService->pszServiceName, &hKey) ==
ERROR_SUCCESS)
+ {
+ /* It worked -- check if we should unload the service when stopped */
+ if (RegQueryValueExW(hKey,
+ L"ServiceDllUnloadOnStop",
+ 0,
+ &dwType,
+ (LPBYTE)&Data,
+ &cbData) == ERROR_SUCCESS)
+ {
+ /* Make sure the data is correctly formatted */
+ if ((dwType == REG_DWORD) && (Data == 1))
+ {
+ /* Does the service still have active threads? */
+ if (pService->cServiceActiveThreadCount != 0)
+ {
+ /* Yep, so we can't kill it just yet */
+ DBG_TRACE("Skip Unload dll %ws for service %ws, "
+ "active threads %d\n",
+ pService->pDll->pszDllPath,
+ pService->pszServiceName,
+ pService->cServiceActiveThreadCount);
+ }
+ else
+ {
+ /* Nope, we're good to go */
+ DBG_TRACE("Unload dll %ws for service %ws\n",
+ pService->pDll->pszDllPath,
+ pService->pszServiceName);
+
+ /* Free the library and clear the module handle */
+ FreeLibrary(pService->pDll->hModule);
+ pService->pDll->hModule = NULL;
+ }
+ }
+ }
+ }
+
+ /* Drop the lock, unload is complete */
+ LeaveCriticalSection(&ListLock);
+
+ /* Close the parameters key if we had it */
+ if (hKey) RegCloseKey(hKey);
+}
+
+VOID
+WINAPI
+SvchostStopCallback (
+ _In_ PVOID Context,
+ _In_ BOOLEAN TimerOrWaitFired
+ )
+{
+ PSVCHOST_CALLBACK_CONTEXT pSvcsStopCbContext = Context;
+ PSVCHOST_STOP_CALLBACK pfnStopCallback;
+
+ /* Hold the lock while we grab the callback */
+ EnterCriticalSection(&ListLock);
+
+ /* Grab the callback, then clear it */
+ ASSERT(pSvcsStopCbContext->pService != NULL);
+ pfnStopCallback = pSvcsStopCbContext->pService->pfnStopCallback;
+ ASSERT(pfnStopCallback != NULL);
+ pSvcsStopCbContext->pService->pfnStopCallback = NULL;
+
+ /* Now release the lock, making sure the above was atomic */
+ LeaveCriticalSection(&ListLock);
+
+ /* Now make the callout */
+ DBG_TRACE("Call stop callback for service %ws, active threads %d\n",
+ pSvcsStopCbContext->pService->pszServiceName,
+ pSvcsStopCbContext->pService->cServiceActiveThreadCount);
+ pfnStopCallback(pSvcsStopCbContext->pContext, TimerOrWaitFired);
+
+ /* Decrement the active threads -- maybe the DLL can unload now */
+ UnloadServiceDll(pSvcsStopCbContext->pService);
+
+ /* We no longer need the context */
+ MemFree(pSvcsStopCbContext);
+}
+
+DWORD
+WINAPI
+SvcRegisterStopCallback (
+ _In_ PHANDLE phNewWaitObject,
+ _In_ LPCWSTR ServiceName,
+ _In_ HANDLE hObject,
+ _In_ PSVCHOST_STOP_CALLBACK pfnStopCallback,
+ _In_ PVOID pContext,
+ _In_ ULONG dwFlags
+ )
+{
+ ULONG i;
+ PSVCHOST_CALLBACK_CONTEXT pSvcsStopCbContext = NULL;
+ PSVCHOST_SERVICE pService = NULL;
+ DWORD dwError = ERROR_SUCCESS;
+
+ /* All parameters must be present */
+ if ((phNewWaitObject == NULL) ||
+ (ServiceName == NULL) ||
+ (hObject == NULL) ||
+ (pfnStopCallback == NULL))
+ {
+ /* Fail otherwise */
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Don't allow new DLLs while we send notifications */
+ EnterCriticalSection(&ListLock);
+
+ /* Scan all registered services */
+ for (i = 0; i < ServiceCount; i++)
+ {
+ /* Search for the service entry matching this service name */
+ if (lstrcmpiW(ServiceName, ServiceArray[i].pszServiceName) == 0)
+ {
+ /* Found it */
+ pService = &ServiceArray[i];
+ break;
+ }
+ }
+
+ /* Do we have a service? Does it already have a callback? */
+ if ((pService == NULL) || (pService->pfnStopCallback != NULL))
+ {
+ /* Affirmative, nothing for us to do */
+ dwError = ERROR_INVALID_DATA;
+ DBG_ERR("Service %ws missing or already registered for callback, "
+ "status %d\n",
+ ServiceName,
+ dwError);
+ goto Quickie;
+ }
+
+ /* Allocate our internal context */
+ pSvcsStopCbContext = MemAlloc(HEAP_ZERO_MEMORY, sizeof(*pSvcsStopCbContext));
+ if (pSvcsStopCbContext == NULL)
+ {
+ /* We failed, bail out */
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ DBG_ERR("MemAlloc for context block for service %ws failed, status "
+ "%d\n",
+ ServiceName,
+ dwError);
+ goto Quickie;
+ }
+
+ /* Setup the context and register for the wait */
+ pSvcsStopCbContext->pContext = pContext;
+ pSvcsStopCbContext->pService = pService;
+ if (RegisterWaitForSingleObject(phNewWaitObject,
+ hObject,
+ SvchostStopCallback,
+ pSvcsStopCbContext,
+ INFINITE,
+ dwFlags))
+ {
+ /* We now have an active thread associated with this wait */
+ pService->cServiceActiveThreadCount++;
+ pService->pfnStopCallback = pfnStopCallback;
+ DBG_TRACE("Registered stop callback for service %ws, active threads
%d\n",
+ ServiceName,
+ pService->cServiceActiveThreadCount);
}
else
{
- DPRINT1("Invalid ServiceDll value type %lu for service: %ls, ErrorCode:
%lu\n", ValueType, ServiceName, GetLastError());
- HeapFree(GetProcessHeap(), 0, Buffer);
- return FALSE;
- }
-
- /* Load the service dll */
- DPRINT("Trying to load dll\n");
- hServiceDll = LoadLibrary(DllPath);
- if (hServiceDll == NULL)
- {
- DPRINT1("Unable to load ServiceDll: %ls, ErrorCode: %lu\n", DllPath,
GetLastError());
- HeapFree(GetProcessHeap(), 0, DllPath);
- return FALSE;
- }
- HeapFree(GetProcessHeap(), 0, DllPath);
-
- ServiceMainFunc = (LPSERVICE_MAIN_FUNCTION)GetProcAddress(hServiceDll,
"ServiceMain");
-
- /* Allocate a service node in the linked list */
- Service = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICE));
- if (Service == NULL)
- {
- DPRINT1("Not enough memory for service: %ls\n", ServiceName);
- return FALSE;
- }
-
- ServiceNameSize = (wcslen(ServiceName) + 1) * sizeof(WCHAR);
- Service->Name = HeapAlloc(GetProcessHeap(), 0, ServiceNameSize);
- if (Service->Name == NULL)
- {
- DPRINT1("Not enough memory for service: %ls\n", ServiceName);
- HeapFree(GetProcessHeap(), 0, Service);
- return FALSE;
- }
- Result = StringCbCopy(Service->Name, ServiceNameSize, ServiceName);
- ASSERT(SUCCEEDED(Result));
- (VOID)Result;
-
- Service->hServiceDll = hServiceDll;
- Service->ServiceMainFunc = ServiceMainFunc;
-
- Service->Next = FirstService;
- FirstService = Service;
-
+ /* Registration failed, bail out */
+ dwError = GetLastError();
+ DBG_ERR("Registration for stop callback for service %ws failed, "
+ "status %d\n",
+ ServiceName,
+ dwError);
+ }
+
+Quickie:
+ /* Drop the lock, and free the context if we failed */
+ LeaveCriticalSection(&ListLock);
+ if (dwError != ERROR_SUCCESS) MemFree(pSvcsStopCbContext);
+ return dwError;
+}
+
+VOID
+WINAPI
+AbortSvchostService (
+ _In_ LPCWSTR lpServiceName,
+ _In_ DWORD dwExitCode
+ )
+{
+ SERVICE_STATUS_HANDLE scHandle;
+ SERVICE_STATUS ServiceStatus;
+
+ /* Make us stopped and accept only query commands */
+ ServiceStatus.dwCheckPoint = 0;
+ ServiceStatus.dwWaitHint = 0;
+ ServiceStatus.dwServiceSpecificExitCode = 0;
+ ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+ ServiceStatus.dwControlsAccepted = SERVICE_QUERY_CONFIG;
+ ServiceStatus.dwServiceType = SERVICE_WIN32;
+ ServiceStatus.dwWin32ExitCode = dwExitCode;
+
+ /* Register a handler that will do nothing while we are being stopped */
+ scHandle = RegisterServiceCtrlHandlerW(lpServiceName,
+ DummySvchostCtrlHandler);
+ if (scHandle)
+ {
+ /* Stop us */
+ if (!SetServiceStatus(scHandle, &ServiceStatus))
+ {
+ /* Tell the debugger if this didn't work */
+ DBG_ERR("AbortSvchostService: SetServiceStatus error %ld\n",
+ GetLastError());
+ }
+ }
+ else
+ {
+ /* Tell the debugger if we couldn't register the handler */
+ DBG_ERR("AbortSvchostService: RegisterServiceCtrlHandler failed %d\n",
+ GetLastError());
+ }
+}
+
+PVOID
+WINAPI
+GetServiceDllFunction (
+ _In_ PSVCHOST_DLL pDll,
+ _In_ LPCSTR lpProcName,
+ _Out_ PDWORD lpdwError
+ )
+{
+ HMODULE hModule;
+ PVOID lpAddress = NULL;
+ ULONG_PTR ulCookie = 0;
+
+ /* Activate the context */
+ if (ActivateActCtx(pDll->hActCtx, &ulCookie) != TRUE)
+ {
+ /* We couldn't, bail out */
+ if (lpdwError) *lpdwError = GetLastError();
+ DBG_ERR("ActivateActCtx for %ws failed. Error %d.\n",
+ pDll->pszDllPath,
+ GetLastError());
+ return lpAddress;
+ }
+
+ /* Check if we already have a loaded module for this service */
+ hModule = pDll->hModule;
+ if (!hModule)
+ {
+ /* We don't -- load it */
+ hModule = LoadLibraryExW(pDll->pszDllPath,
+ NULL,
+ LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hModule)
+ {
+ /* We failed to load it, bail out */
+ if (lpdwError) *lpdwError = GetLastError();
+ DBG_ERR("LoadLibrary (%ws) failed. Error %d.\n",
+ pDll->pszDllPath,
+ GetLastError());
+ DeactivateActCtx(0, ulCookie);
+ return lpAddress;
+ }
+
+ /* Loaded! */
+ pDll->hModule = hModule;
+ }
+
+ /* Next, get the address being looked up*/
+ lpAddress = GetProcAddress(hModule, lpProcName);
+ if (!lpAddress)
+ {
+ /* We couldn't find it, write the error code and a debug statement */
+ if (lpdwError) *lpdwError = GetLastError();
+ DBG_ERR("GetProcAddress (%s) failed on DLL %ws. Error %d.\n",
+ lpProcName,
+ pDll->pszDllPath,
+ GetLastError());
+ }
+
+ /* All done, get rid of the activation context */
+ DeactivateActCtx(0, ulCookie);
+ return lpAddress;
+}
+
+PSVCHOST_DLL
+WINAPI
+FindDll (
+ _In_ LPCWSTR pszManifestPath,
+ _In_ LPCWSTR pszDllPath,
+ _In_ PSVCHOST_SERVICE pService
+ )
+{
+ PSVCHOST_DLL pDll, pFoundDll = NULL;
+ PLIST_ENTRY pNextEntry;
+ ASSERT(pszDllPath);
+
+ /* Lock the DLL database */
+ EnterCriticalSection(&ListLock);
+
+ /* Scan through the database */
+ pNextEntry = DllList.Flink;
+ while (pNextEntry != &DllList)
+ {
+ /* Search for an existing DLL with the same parameters */
+ pDll = CONTAINING_RECORD(pNextEntry, SVCHOST_DLL, DllList);
+ if ((lstrcmpW(pDll->pszDllPath, pszDllPath) == 0) &&
+ (lstrcmpW(pDll->pszManifestPath, pszManifestPath) == 0) &&
+ (lstrcmpW(pDll->pService->pszServiceName, pService->pszServiceName)
== 0))
+ {
+ /* Found it! */
+ pFoundDll = pDll;
+ break;
+ }
+
+ /* Keep searching */
+ pNextEntry = pNextEntry->Flink;
+ }
+
+ /* All done, release the lock and return what we found, if anything */
+ LeaveCriticalSection(&ListLock);
+ return pFoundDll;
+}
+
+PSVCHOST_DLL
+WINAPI
+AddDll (
+ _In_ LPCWSTR pszManifestPath,
+ _In_ LPCWSTR pszDllPath,
+ _In_ PSVCHOST_SERVICE pService,
+ _Out_ PDWORD lpdwError
+ )
+{
+ PSVCHOST_DLL pDll;
+ ULONG nDllPathLength, nManifestPathLength;
+ ASSERT(pszDllPath);
+ ASSERT(*pszDllPath);
+
+ /* Compute the length of the two paths */
+ nDllPathLength = lstrlenW(pszDllPath);
+ nManifestPathLength = lstrlenW(pszManifestPath);
+
+ /* Allocate the DLL entry for this service */
+ pDll = MemAlloc(HEAP_ZERO_MEMORY,
+ sizeof(*pDll) +
+ (nDllPathLength + nManifestPathLength) * sizeof(WCHAR) +
+ 2 * sizeof(UNICODE_NULL));
+ if (pDll == NULL)
+ {
+ /* Bail out with failure */
+ *lpdwError = ERROR_NOT_ENOUGH_MEMORY;
+ return pDll;
+ }
+
+ /* Put the DLL path right after the DLL entry */
+ pDll->pszDllPath = (LPCWSTR)(pDll + 1);
+
+ /* Put the manifest path right past the DLL path (note the pointer math) */
+ pDll->pszManifestPath = pDll->pszDllPath + nDllPathLength + 1;
+
+ /* Now copy both paths */
+ CopyMemory((PVOID)pDll->pszDllPath,
+ pszDllPath,
+ sizeof(WCHAR) * nDllPathLength);
+ CopyMemory((PVOID)pDll->pszManifestPath,
+ pszManifestPath,
+ sizeof(WCHAR) * nManifestPathLength);
+
+ /* Now set the service, and make sure both paths are NULL-terminated */
+ pDll->pService = pService;
+ ASSERT(pDll->hActCtx == NULL);
+ ASSERT(pDll->pszDllPath[nDllPathLength] == UNICODE_NULL);
+ ASSERT(pDll->pszManifestPath[nManifestPathLength] == UNICODE_NULL);
+
+ /* Finally, add the entry to the DLL database, while holding the lock */
+ EnterCriticalSection(&ListLock);
+ InsertTailList(&DllList, &pDll->DllList);
+ LeaveCriticalSection(&ListLock);
+
+ /* And return it */
+ return pDll;
+}
+
+VOID
+WINAPI
+GetServiceMainFunctions (
+ _In_ PSVCHOST_SERVICE pService,
+ _Out_ PVOID *pServiceMain,
+ _Out_ PVOID *pPushServiceGlobals,
+ _Out_ PDWORD lpdwError
+ )
+{
+ DWORD dwError, cbDllLength, cbData, dwType;
+ PSVCHOST_DLL pDll;
+ ACTCTXW actCtx;
+ LPCWSTR pszDllPath;
+ HKEY hKey;
+ HANDLE hActCtx;
+ LPWSTR lpData;
+ WCHAR szDllBuffer[MAX_PATH + 2], szManifestBuffer[MAX_PATH + 2];
+
+ /* Initialize the activation context we might need later */
+ RtlZeroMemory(&actCtx, sizeof(actCtx));
+ actCtx.cbSize = sizeof(actCtx);
+
+ /* We clean these up in our failure path so initialize them to NULL here */
+ hActCtx = NULL;
+ hKey = NULL;
+ lpData = NULL;
+ *lpdwError = ERROR_SUCCESS;
+
+ /* Null terminate the string buffers */
+ szDllBuffer[0] = UNICODE_NULL;
+ szManifestBuffer[0] = UNICODE_NULL;
+
+ /* Do we already have a DLL ready to go for this service? */
+ pDll = pService->pDll;
+ if (pDll != NULL) goto HaveDll;
+
+ /* Nope, we're starting from scratch. Open a handle to parameters key */
+ dwError = OpenServiceParametersKey(pService->pszServiceName, &hKey);
+ if (dwError)
+ {
+ *lpdwError = dwError;
+ ASSERT(*lpdwError != NO_ERROR);
+ goto Quickie;
+ }
+
+ /* Allocate enough space to hold a unicode path (NULL-terminated) */
+ cbData = MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL);
+ lpData = MemAlloc(0, cbData);
+ if (lpData == NULL)
+ {
+ /* No memory, bail out */
+ *lpdwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto Quickie;
+ }
+
+ /* Query the DLL path */
+ lpData[0] = UNICODE_NULL;
+ dwError = RegQueryValueExW(hKey,
+ L"ServiceDll",
+ 0,
+ &dwType,
+ (LPBYTE)lpData,
+ &cbData);
+ if (dwError != ERROR_SUCCESS)
+ {
+ *lpdwError = dwError;
+ DBG_ERR("RegQueryValueEx for the ServiceDll parameter of the %ws "
+ "service returned %u\n",
+ pService->pszServiceName,
+ dwError);
+ goto Quickie;
+ }
+
+ /* Is the registry data valid and present? */
+ if ((dwType != REG_EXPAND_SZ) || (lpData[0] == UNICODE_NULL))
+ {
+ /* Nope, bail out */
+ *lpdwError = ERROR_FILE_NOT_FOUND;
+ DBG_ERR("The ServiceDll parameter for the %ws service is not of type "
+ "REG_EXPAND_SZ\n",
+ pService->pszServiceName);
+ goto Quickie;
+ }
+
+ /* Convert the expandable path into an absolute path */
+ ExpandEnvironmentStringsW(lpData, szDllBuffer, MAX_PATH);
+ SvchostCharLowerW(szDllBuffer);
+
+ /* Check if the service has a manifest file associated with it */
+ cbData = MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL);
+ dwError = RegQueryValueExW(hKey,
+ L"ServiceManifest",
+ NULL,
+ &dwType,
+ (LPBYTE)lpData,
+ &cbData);
+ if (dwError != ERROR_SUCCESS)
+ {
+ /* Did we fail because one wasn't set? */
+ if ((dwError != ERROR_PATH_NOT_FOUND) &&
+ (dwError != ERROR_FILE_NOT_FOUND))
+ {
+ /* We failed for some other reason, bail out */
+ *lpdwError = dwError;
+ DBG_ERR("RegQueryValueEx for the ServiceManifest parameter of the
"
+ "%ws service returned %u\n",
+ pService->pszServiceName,
+ dwError);
+ goto Quickie;
+ }
+
+ /* We have no manifest, make sure the buffer is empty */
+ szManifestBuffer[0] = UNICODE_NULL;
+
+ /* We're done with this buffer */
+ MemFree(lpData);
+ lpData = NULL;
+
+ /* Use the whole DLL path, since we don't have a manifest */
+ pszDllPath = szDllBuffer;
+ }
+ else
+ {
+ /* Do we have invalid registry data? */
+ if ((dwType != REG_EXPAND_SZ) || (*lpData == UNICODE_NULL))
+ {
+ /* Yes, pretend there's no manifest and bail out */
+ *lpdwError = ERROR_FILE_NOT_FOUND;
+ DBG_ERR("The ServiceManifest parameter for the %ws service is not
"
+ "of type REG_EXPAND_SZ\n",
+ pService->pszServiceName);
+ goto Quickie;
+ }
+
+ /* Expand the string into our stack buffer */
+ ExpandEnvironmentStringsW(lpData, szManifestBuffer, MAX_PATH);
+
+ /* We no longer need the heap buffer*/
+ MemFree(lpData);
+ lpData = NULL;
+
+ /* Lowercase the manifest path */
+ SvchostCharLowerW(szManifestBuffer);
+
+ /* Now loop over the DLL path */
+ cbDllLength = lstrlenW(szDllBuffer);
+ while (cbDllLength)
+ {
+ /* From the end, until we find the first path separator */
+ if (szDllBuffer[cbDllLength] == '\\' || szDllBuffer[cbDllLength] ==
'/')
+ {
+ /* Use just a short name (cut out the rest of the path) */
+ pszDllPath = &szDllBuffer[cbDllLength + 1];
+ break;
+ }
+
+ /* Try the next character */
+ cbDllLength--;
+ }
+ }
+
+ /* See if we already have a matching DLL and manifest for this service */
+ pDll = FindDll(szManifestBuffer, pszDllPath, pService);
+ if (pDll == NULL)
+ {
+ /* We don't have it yet -- does this DLL have a manifest? */
+ if (szManifestBuffer[0] != UNICODE_NULL)
+ {
+ /* Create an activation context for it */
+ actCtx.lpSource = szManifestBuffer;
+ hActCtx = CreateActCtxW(&actCtx);
+ if (hActCtx == INVALID_HANDLE_VALUE)
+ {
+ /* We've failed to create one, bail out */
+ *lpdwError = GetLastError();
+ DBG_ERR("CreateActCtxW(%ws) for the %ws service returned
%u\n",
+ szManifestBuffer,
+ pService->pszServiceName,
+ *lpdwError);
+ goto Quickie;
+ }
+ }
+
+ /* Add this new DLL into the database */
+ pDll = AddDll(szManifestBuffer, pszDllPath, pService, lpdwError);
+ if (pDll)
+ {
+ /* Save the activation context and zero it so we don't release later */
+ pDll->hActCtx = hActCtx;
+ hActCtx = NULL;
+ }
+ }
+
+ /* We either found, added, or failed to add, the DLL for this service */
+ ASSERT(!pService->pDll);
+ pService->pDll = pDll;
+
+ /* In all cases, we will query the ServiceMain function, however*/
+ RegQueryStringA(hKey,
+ L"ServiceMain",
+ REG_SZ,
+ &pService->pszServiceMain);
+
+ /* And now we'll check if we were able to create it earlier (or find it) */
+ if (!pService->pDll)
+ {
+ /* We were not, so there's no point in going on */
+ ASSERT(*lpdwError != NO_ERROR);
+ goto Quickie;
+ }
+
+ /* We do have a valid DLL, so now get the service main routine out of it */
+HaveDll:
+ *pServiceMain = GetServiceDllFunction(pDll,
+ pService->pszServiceMain ?
+ pService->pszServiceMain :
+ "ServiceMain",
+ lpdwError);
+
+ /* And now get the globals routine out of it (this one is optional) */
+ *pPushServiceGlobals = GetServiceDllFunction(pDll,
+ "SvchostPushServiceGlobals",
+ NULL);
+
+Quickie:
+ /* We're done, cleanup any resources we left behind */
+ if (hKey != NULL) RegCloseKey(hKey);
+ if (lpData != NULL) MemFree(lpData);
+ if ((hActCtx) && (hActCtx != INVALID_HANDLE_VALUE)) ReleaseActCtx(hActCtx);
+}
+
+VOID
+WINAPI
+ServiceStarter (
+ _In_ DWORD dwNumServicesArgs,
+ _In_ LPWSTR *lpServiceArgVectors
+ )
+{
+ DWORD i, dwError = ERROR_FILE_NOT_FOUND;
+ PSVCHOST_SERVICE ServiceEntry;
+ LPCWSTR lpServiceName;
+ LPSERVICE_MAIN_FUNCTIONW ServiceMain = NULL;
+ PSVCHOST_INIT_GLOBALS ServiceInitGlobals = NULL;
+
+ /* Hold the lock while we start a service */
+ EnterCriticalSection(&ListLock);
+
+ /* Get this service's name, and loop the database */
+ lpServiceName = *lpServiceArgVectors;
+ for (i = 0; i < ServiceCount; i++)
+ {
+ /* Try to find a match by name */
+ if (!lstrcmpiW(lpServiceName, ServiceArray[i].pszServiceName)) break;
+ }
+
+ /* Check if we didn't find it */
+ if (i == ServiceCount)
+ {
+ /* This looks like a bogus attempt, bail out */
+ LeaveCriticalSection(&ListLock);
+ return;
+ }
+
+ /* We have it */
+ ServiceEntry = &ServiceArray[i];
+
+ /* Should we breakpoint before loading this service? */
+ if (FDebugBreakForService(lpServiceName) != FALSE)
+ {
+ /* Yep -- do it */
+ DBG_TRACE("Attaching debugger before getting ServiceMain for
%ws...\n",
+ lpServiceName);
+ DebugBreak();
+ }
+
+ /* Get the callbacks for this service */
+ GetServiceMainFunctions(&ServiceArray[i],
+ (PVOID*)&ServiceMain,
+ (PVOID*)&ServiceInitGlobals,
+ &dwError);
+
+ /* If this service is valid and needs globals, but we don't have them... */
+ if ((ServiceMain != NULL) &&
+ (ServiceInitGlobals != NULL) &&
+ (g_pSvchostSharedGlobals == NULL))
+ {
+ /* Go and build them for the first time! */
+ SvchostBuildSharedGlobals();
+ }
+
+ /* We call a service if it has a main, or if wants globals and we have them */
+ if (((ServiceInitGlobals != NULL) && (g_pSvchostSharedGlobals != NULL)) ||
+ ((ServiceMain != NULL) && (ServiceInitGlobals == NULL)))
+ {
+ /* Therefore, make sure it won't be unloaded as we drop the lock */
+ ServiceEntry->cServiceActiveThreadCount++;
+ }
+
+ /* Drop the lock while we call into the service DLL */
+ LeaveCriticalSection(&ListLock);
+
+ /* First: does this service want globals? */
+ if (ServiceInitGlobals != NULL)
+ {
+ /* Do we have any to give? */
+ if (g_pSvchostSharedGlobals != NULL)
+ {
+ /* Yes, push them to the service */
+ ServiceInitGlobals(g_pSvchostSharedGlobals);
+
+ /* Does the service NOT have an entrypoint? */
+ if (ServiceMain == NULL)
+ {
+ /* We're going to abort loading, it serves no use */
+ if (lpServiceName != NULL)
+ {
+ AbortSvchostService(lpServiceName, dwError);
+ }
+
+ /* And drop a reference count since it's not active anymore */
+ UnloadServiceDll(ServiceEntry);
+ }
+ }
+ else if (lpServiceName != NULL)
+ {
+ /* We have no globals to give, so don't even bother calling it */
+ AbortSvchostService(lpServiceName, dwError);
+ }
+ }
+
+ /* Next up, does it have an entrypoint? */
+ if (ServiceMain != NULL)
+ {
+ /* It does, so call it */
+ DBG_TRACE("Calling ServiceMain for %ws...\n", lpServiceName);
+ ServiceMain(dwNumServicesArgs, lpServiceArgVectors);
+
+ /* We're out of the service now, so we can drop a reference */
+ UnloadServiceDll(ServiceEntry);
+ }
+ else if (lpServiceName != NULL)
+ {
+ /* It has no entrypoint, so abort its launch */
+ AbortSvchostService(lpServiceName, dwError);
+ }
+}
+
+SERVICE_TABLE_ENTRYW*
+WINAPI
+BuildServiceTable (
+ VOID
+ )
+{
+ SERVICE_TABLE_ENTRYW *pServiceTable;
+ ULONG i;
+
+ /* Acquire the database lock while we go over the services */
+ EnterCriticalSection(&ListLock);
+
+ /* Allocate space for a NULL entry at the end as well, Windows needs this */
+ pServiceTable = MemAlloc(HEAP_ZERO_MEMORY,
+ (ServiceCount + 1) * sizeof(*pServiceTable));
+ if (pServiceTable)
+ {
+ /* Go over all our registered services */
+ for (i = 0; i < ServiceCount; i++)
+ {
+ /* And set their parameters in the service table */
+ pServiceTable[i].lpServiceName = (LPWSTR)ServiceArray[i].pszServiceName;
+ pServiceTable[i].lpServiceProc = ServiceStarter;
+ DBG_TRACE("Added service table entry for %ws\n",
+ pServiceTable[i].lpServiceName);
+ }
+ }
+
+ /* All done, can release the lock now */
+ LeaveCriticalSection(&ListLock);
+ return pServiceTable;
+}
+
+BOOLEAN
+WINAPI
+CallPerInstanceInitFunctions (
+ _In_ PSVCHOST_OPTIONS pOptions
+ )
+{
+ PIMAGE_NT_HEADERS pNtHeaders;
+ BOOLEAN bResult;
+
+ /* Is COM required for this host? */
+ if (pOptions->CoInitializeSecurityParam != 0)
+ {
+ /* Yes, initialize COM security and parameters */
+ bResult = InitializeSecurity(pOptions->CoInitializeSecurityParam,
+ pOptions->AuthenticationLevel,
+ pOptions->ImpersonationLevel,
+ pOptions->AuthenticationCapabilities);
+ if (bResult != TRUE) return FALSE;
+ }
+
+ /* Do we have a custom RPC stack size? */
+ if (pOptions->DefaultRpcStackSize != 0)
+ {
+ /* Yes, go set it */
+ RpcMgmtSetServerStackSize(pOptions->DefaultRpcStackSize << 10);
+ }
+ else
+ {
+ /* Nope, get the NT headers from the image */
+ pNtHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
+ if (pNtHeaders)
+ {
+ /* And just use whatever the default thread stack is */
+ RpcMgmtSetServerStackSize(pNtHeaders->OptionalHeader.SizeOfStackCommit);
+ }
+ }
+
+ /* Is this host holding critical services? */
+ if (pOptions->SystemCritical != FALSE)
+ {
+ /* Mark the process as critical if so */
+ RtlSetProcessIsCritical(TRUE, NULL, TRUE);
+ }
+
+ /* All done */
return TRUE;
}
-VOID FreeServices(VOID)
-{
- while (FirstService)
- {
- PSERVICE Service = FirstService;
- FirstService = Service->Next;
-
- FreeLibrary(Service->hServiceDll);
-
- HeapFree(GetProcessHeap(), 0, Service->Name);
- HeapFree(GetProcessHeap(), 0, Service);
- }
-}
-
-/*
- * Returns the number of services successfully loaded from the category
- */
-DWORD LoadServiceCategory(PCWSTR ServiceCategory)
-{
- HKEY hServicesKey;
- DWORD ValueType;
- WCHAR Buffer[REG_MAX_DATA_SIZE];
- DWORD BufferSize = sizeof(Buffer);
- PCWSTR ServiceName;
- DWORD BufferIndex = 0;
- DWORD NrOfServices = 0;
- LONG RetVal;
-
- /* Get all the services in this category */
- RetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SVCHOST_REG_KEY, 0, KEY_READ,
&hServicesKey);
- if (RetVal != ERROR_SUCCESS)
- {
- DPRINT1("Could not open service category: %ls\n", ServiceCategory);
- return 0;
- }
-
- RetVal = RegQueryValueEx(hServicesKey, ServiceCategory, NULL, &ValueType,
(LPBYTE)Buffer, &BufferSize);
- if (RetVal != ERROR_SUCCESS)
- {
- DPRINT1("Could not open service category (2): %ls\n",
ServiceCategory);
- RegCloseKey(hServicesKey);
- return 0;
- }
-
- /* Clean up */
- RegCloseKey(hServicesKey);
-
- /* Load services in the category */
- ServiceName = Buffer;
- while (ServiceName[0] != UNICODE_NULL)
- {
- size_t Length;
-
- Length = wcslen(ServiceName);
- if (Length == 0)
- break;
-
- if (PrepareService(ServiceName))
- ++NrOfServices;
-
- BufferIndex += Length + 1;
-
- ServiceName = &Buffer[BufferIndex];
- }
-
- return NrOfServices;
-}
-
-int wmain(int argc, wchar_t **argv)
-{
- DWORD NrOfServices;
- LPSERVICE_TABLE_ENTRY ServiceTable;
-
- if (argc < 3)
- {
- /* MS svchost.exe doesn't seem to print help, should we? */
- return 0;
- }
-
- if (wcscmp(argv[1], L"-k"))
- {
- /* For now, we only handle "-k" */
- return 0;
- }
-
- NrOfServices = LoadServiceCategory(argv[2]);
-
- DPRINT("NrOfServices: %lu\n", NrOfServices);
- if (NrOfServices == 0)
- return 0;
-
- ServiceTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_TABLE_ENTRY) *
(NrOfServices + 1));
- if (ServiceTable != NULL)
- {
- DWORD i;
- PSERVICE Service = FirstService;
-
- /* Fill the service table */
- for (i = 0; i < NrOfServices; i++)
- {
- DPRINT("Loading service: %ls\n", Service->Name);
- ServiceTable[i].lpServiceName = Service->Name;
- ServiceTable[i].lpServiceProc = Service->ServiceMainFunc;
- Service = Service->Next;
- }
- ASSERT(Service == NULL);
-
- /* Set a NULL entry to end the service table */
- ServiceTable[i].lpServiceName = NULL;
- ServiceTable[i].lpServiceProc = NULL;
-
- if (!StartServiceCtrlDispatcher(ServiceTable))
- DPRINT1("Failed to start service control dispatcher, ErrorCode:
%lu\n", GetLastError());
-
- HeapFree(GetProcessHeap(), 0, ServiceTable);
- }
- else
- {
- DPRINT1("Not enough memory for the service table, trying to allocate %u
bytes\n", sizeof(SERVICE_TABLE_ENTRY) * (NrOfServices + 1));
- }
-
- DPRINT("Freeing services...\n");
- FreeServices();
-
- return 0;
-}
-
-/* EOF */
+VOID
+wmainCRTStartup (
+ VOID
+ )
+{
+ PSVCHOST_OPTIONS lpOptions;
+ SERVICE_TABLE_ENTRYW *pServiceTable;
+ LPWSTR pszCmdLine;
+
+ /* Set a generic SEH filter and hard fail all critical errors */
+ SetUnhandledExceptionFilter(SvchostUnhandledExceptionFilter);
+ SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ /* Initialize the heap allocator */
+ MemInit(GetProcessHeap());
+
+ /* Initialize the DLL database and lock */
+ InitializeListHead(&DllList);
+ InitializeCriticalSection(&ListLock);
+
+ /* Get the command-line and parse it to get the service group */
+ pszCmdLine = GetCommandLineW();
+ lpOptions = BuildCommandOptions(pszCmdLine);
+ if (lpOptions == NULL)
+ {
+ /* Without a valid command-line, there's nothing for us to do */
+ DBG_TRACE("Calling ExitProcess for %ws\n", pszCmdLine);
+ ExitProcess(0);
+ }
+
+ /* Now use the service group information to lookup all the services */
+ BuildServiceArray(lpOptions);
+
+ /* Convert the list of services in this group to the SCM format */
+ pServiceTable = BuildServiceTable();
+ if (pServiceTable == NULL)
+ {
+ /* This is critical, bail out without it */
+ MemFree(lpOptions);
+ return;
+ }
+
+ /* Initialize COM and RPC as needed for this service group */
+ if (CallPerInstanceInitFunctions(lpOptions) == FALSE)
+ {
+ /* Exit with a special code indicating COM/RPC setup has failed */
+ DBG_ERR("%s", "CallPerInstanceInitFunctions failed --
exiting!\n");
+ ExitProcess(1);
+ }
+
+ /* We're ready to go -- free the options buffer */
+ MemFree(lpOptions);
+
+ /* And call into ADVAPI32 to get our services going */
+ StartServiceCtrlDispatcherW(pServiceTable);
+}
Modified: trunk/reactos/base/services/svchost/svchost.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/svchost/svch…
==============================================================================
--- trunk/reactos/base/services/svchost/svchost.h [iso-8859-1] (original)
+++ trunk/reactos/base/services/svchost/svchost.h [iso-8859-1] Wed Aug 28 08:32:27 2013
@@ -1,32 +1,303 @@
/*
- * PROJECT: ReactOS SvcHost
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: /base/services/svchost/svchost.h
- * PURPOSE: Provide dll service loader
- * PROGRAMMERS: Gregor Brunmar (gregor.brunmar(a)home.se)
+ * PROJECT: ReactOS Service Host
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * FILE: base/services/svchost/svchost.h
+ * PURPOSE: Precompiled Header for Service Host
+ * PROGRAMMERS: ReactOS Portable Systems Group
*/
#pragma once
-
-/* INCLUDES ******************************************************************/
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <windef.h>
-#include <winbase.h>
-#include <winreg.h>
-#include <winsvc.h>
-#include <strsafe.h>
-
-/* DEFINES *******************************************************************/
-
-typedef struct _SERVICE {
- PWSTR Name;
- HINSTANCE hServiceDll;
- LPSERVICE_MAIN_FUNCTION ServiceMainFunc;
- struct _SERVICE *Next;
-} SERVICE, *PSERVICE;
-
-/* FUNCTIONS *****************************************************************/
-
-/* EOF */
+#define WIN32_NO_STATUS
+#include <Windows.h>
+#include <AclAPI.h>
+#include <ntndk.h>
+#include <lmerr.h>
+
+//
+// FIXME: Should go in public headers
+//
+#define DPFLTR_SVCHOST_ID 28
+
+//
+// This prints out a SVCHOST-specific debug print, with the PID/TID
+//
+#if _EX_
+#define SvchostDbgPrint(l, x, ...) \
+ DbgPrintEx(DPFLTR_SVCHOST_ID, \
+ DPFLTR_MASK | l, \
+ "[SVCHOST] %lx.%lx: " # x, \
+ GetCurrentProcessId(), \
+ GetCurrentThreadId(), \
+ __VA_ARGS__);
+#else
+#define SvchostDbgPrint(l, x, ...) \
+ DbgPrint("[SVCHOST] %lx.%lx: " # x, \
+ GetCurrentProcessId(), \
+ GetCurrentThreadId(), \
+ __VA_ARGS__);
+#endif
+#define DBG_ERR(x, ...) SvchostDbgPrint(1, x, __VA_ARGS__)
+#define DBG_TRACE(x, ...) SvchostDbgPrint(4, x, __VA_ARGS__)
+
+//
+// This is the callback that a hosted service can register for stop notification
+// FIXME: GLOBAL HEADER
+//
+typedef VOID
+ (*CALLBACK PSVCHOST_STOP_CALLBACK) (
+ _In_ PVOID lpParameter,
+ _In_ BOOLEAN TimerOrWaitFired
+ );
+
+//
+// Hosted Services and SvcHost Use this Structure
+// FIXME: GLOBAL HEADER
+//
+typedef struct _SVCHOST_GLOBALS
+{
+ PVOID NullSid;
+ PVOID WorldSid;
+ PVOID LocalSid;
+ PVOID NetworkSid;
+ PVOID LocalSystemSid;
+ PVOID LocalServiceSid;
+ PVOID NetworkServiceSid;
+ PVOID BuiltinDomainSid;
+ PVOID AuthenticatedUserSid;
+ PVOID AnonymousLogonSid;
+ PVOID AliasAdminsSid;
+ PVOID AliasUsersSid;
+ PVOID AliasGuestsSid;
+ PVOID AliasPowerUsersSid;
+ PVOID AliasAccountOpsSid;
+ PVOID AliasSystemOpsSid;
+ PVOID AliasPrintOpsSid;
+ PVOID AliasBackupOpsSid;
+ PVOID RpcpStartRpcServer;
+ PVOID RpcpStopRpcServer;
+ PVOID RpcpStopRpcServerEx;
+ PVOID SvcNetBiosOpen;
+ PVOID SvcNetBiosClose;
+ PVOID SvcNetBiosReset;
+ PVOID SvcRegisterStopCallback;
+} SVCHOST_GLOBALS, *PSVCHOST_GLOBALS;
+
+//
+// This is the callback for them to receive it
+//
+typedef VOID
+(WINAPI *PSVCHOST_INIT_GLOBALS) (
+ _In_ PSVCHOST_GLOBALS Globals
+);
+//
+// Initialization Stages
+//
+#define SVCHOST_RPC_INIT_COMPLETE 1
+#define SVCHOST_NBT_INIT_COMPLETE 2
+#define SVCHOST_SID_INIT_COMPLETE 4
+
+//
+// Domain Alias SID Structure
+//
+typedef struct _DOMAIN_SID_DATA
+{
+ PSID Sid;
+ DWORD SubAuthority;
+} DOMAIN_SID_DATA;
+
+//
+// Well-known SID Structure
+//
+typedef struct _SID_DATA
+{
+ PSID Sid;
+ SID_IDENTIFIER_AUTHORITY Authority;
+ DWORD SubAuthority;
+} SID_DATA;
+
+//
+// This contains all the settings (from the registry) for a hosted service
+//
+typedef struct _SVCHOST_OPTIONS
+{
+ PWCHAR CmdLineBuffer;
+ PWCHAR CmdLine;
+ BOOL HasServiceGroup;
+ LPWSTR ServiceGroupName;
+ DWORD CoInitializeSecurityParam;
+ DWORD AuthenticationLevel;
+ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
+ DWORD AuthenticationCapabilities;
+ DWORD DefaultRpcStackSize;
+ BOOLEAN SystemCritical;
+} SVCHOST_OPTIONS, *PSVCHOST_OPTIONS;
+
+//
+// This represents the DLL used to hold a hosted service
+//
+typedef struct _SVCHOST_DLL
+{
+ LIST_ENTRY DllList;
+ HINSTANCE hModule;
+ LPCWSTR pszDllPath;
+ LPCWSTR pszManifestPath;
+ HANDLE hActCtx;
+ struct _SVCHOST_SERVICE* pService;
+} SVCHOST_DLL, *PSVCHOST_DLL;
+
+//
+// This represents an actual hosted service
+//
+typedef struct _SVCHOST_SERVICE
+{
+ LPCWSTR pszServiceName;
+ LPCSTR pszServiceMain;
+ LONG cServiceActiveThreadCount;
+ PSVCHOST_DLL pDll;
+ PSVCHOST_STOP_CALLBACK pfnStopCallback;
+} SVCHOST_SERVICE, *PSVCHOST_SERVICE;
+
+//
+// This is the context that a hosted service with a stop callback has
+//
+typedef struct _SVCHOST_CALLBACK_CONTEXT
+{
+ PVOID pContext;
+ PSVCHOST_SERVICE pService;
+} SVCHOST_CALLBACK_CONTEXT, *PSVCHOST_CALLBACK_CONTEXT;
+
+NTSTATUS
+NTAPI
+RpcpInitRpcServer (
+ VOID
+);
+
+NTSTATUS
+NTAPI
+RpcpStopRpcServer (
+ _In_ RPC_IF_HANDLE IfSpec
+);
+
+NTSTATUS
+NTAPI
+RpcpStopRpcServerEx (
+ _In_ RPC_IF_HANDLE IfSpec
+);
+
+NTSTATUS
+NTAPI
+RpcpStartRpcServer (
+ _In_ LPCWSTR IfName,
+ _In_ RPC_IF_HANDLE IfSpec
+);
+
+VOID
+WINAPI
+SvchostBuildSharedGlobals (
+ VOID
+);
+
+VOID
+WINAPI
+SvchostCharLowerW (
+ _In_ LPCWSTR lpSrcStr
+);
+
+NTSTATUS
+NTAPI
+ScCreateWellKnownSids (
+ VOID
+);
+
+VOID
+WINAPI
+MemInit (
+ _In_ HANDLE Heap
+);
+
+BOOL
+WINAPI
+MemFree (
+ _In_ LPVOID lpMem
+);
+
+PVOID
+WINAPI
+MemAlloc (
+ _In_ DWORD dwFlags,
+ _In_ DWORD dwBytes
+);
+
+VOID
+WINAPI
+SvcNetBiosInit (
+ VOID
+);
+
+VOID
+WINAPI
+SvcNetBiosClose (
+VOID
+);
+
+VOID
+WINAPI
+SvcNetBiosOpen (
+ VOID
+);
+
+DWORD
+WINAPI
+SvcNetBiosReset (
+ _In_ UCHAR LanaNum
+);
+
+BOOL
+WINAPI
+InitializeSecurity (
+ _In_ DWORD dwParam,
+ _In_ DWORD dwAuthnLevel,
+ _In_ DWORD dwImpLevel,
+ _In_ DWORD dwCapabilities
+);
+
+
+DWORD
+WINAPI
+RegQueryDword (
+ _In_ HKEY hKey,
+ _In_ LPCWSTR pszValueName,
+ _Out_ PDWORD pdwValue
+);
+
+DWORD
+WINAPI
+RegQueryString (
+ _In_ HKEY hKey,
+ _In_ LPCWSTR pszValueName,
+ _In_ DWORD dwExpectedType,
+ _Out_ PBYTE* ppbData
+);
+
+DWORD
+WINAPI
+RegQueryStringA (
+ _In_ HKEY hKey,
+ _In_ LPCWSTR pszValueName,
+ _In_ DWORD dwExpectedType,
+ _Out_ LPCSTR* ppszData
+);
+
+DWORD
+WINAPI
+SvcRegisterStopCallback (
+ _In_ PHANDLE phNewWaitObject,
+ _In_ LPCWSTR ServiceName,
+ _In_ HANDLE hObject,
+ _In_ PSVCHOST_STOP_CALLBACK pfnStopCallback,
+ _In_ PVOID pContext,
+ _In_ ULONG dwFlags
+);
+
+extern PSVCHOST_GLOBALS g_pSvchostSharedGlobals;
+