[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.htm, 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).

svn path=/trunk/; revision=59847
This commit is contained in:
Alex Ionescu 2013-08-28 08:32:27 +00:00
parent bbf30d28f7
commit 3acd542293
8 changed files with 2589 additions and 283 deletions

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}

File diff suppressed because it is too large Load diff

View file

@ -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@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
#define WIN32_NO_STATUS
#include <Windows.h>
#include <AclAPI.h>
#include <ntndk.h>
#include <lmerr.h>
/* INCLUDES ******************************************************************/
//
// FIXME: Should go in public headers
//
#define DPFLTR_SVCHOST_ID 28
#include <stdlib.h>
#include <stdarg.h>
#include <windef.h>
#include <winbase.h>
#include <winreg.h>
#include <winsvc.h>
#include <strsafe.h>
//
// 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__)
/* DEFINES *******************************************************************/
//
// 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
);
typedef struct _SERVICE {
PWSTR Name;
HINSTANCE hServiceDll;
LPSERVICE_MAIN_FUNCTION ServiceMainFunc;
struct _SERVICE *Next;
} SERVICE, *PSERVICE;
//
// 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;
/* FUNCTIONS *****************************************************************/
//
// 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;
/* EOF */