mirror of
https://github.com/reactos/reactos.git
synced 2024-11-06 06:33:08 +00:00
6afbc8f483
svn path=/branches/reactos-yarotows/; revision=45219
1236 lines
38 KiB
C
1236 lines
38 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS CSR Sub System
|
|
* FILE: subsys/csr/csrsrv/init.c
|
|
* PURPOSE: CSR Server DLL Initialization
|
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include "srv.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* DATA **********************************************************************/
|
|
|
|
HANDLE CsrObjectDirectory;
|
|
ULONG SessionId;
|
|
BOOLEAN CsrProfileControl;
|
|
UNICODE_STRING CsrDirectoryName;
|
|
HANDLE CsrHeap;
|
|
HANDLE BNOLinksDirectory;
|
|
HANDLE SessionObjectDirectory;
|
|
HANDLE DosDevicesDirectory;
|
|
HANDLE CsrInitializationEvent;
|
|
SYSTEM_BASIC_INFORMATION CsrNtSysInfo;
|
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
/*++
|
|
* @name CsrPopulateDosDevicesDirectory
|
|
*
|
|
* The CsrPopulateDosDevicesDirectory routine uses the DOS Device Map from the
|
|
* Kernel to populate the Dos Devices Object Directory for the session.
|
|
*
|
|
* @param TODO.
|
|
*
|
|
* @return TODO.
|
|
*
|
|
* @remarks TODO.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
NTAPI
|
|
CsrPopulateDosDevicesDirectory(IN HANDLE hDosDevicesDirectory,
|
|
IN PPROCESS_DEVICEMAP_INFORMATION DeviceMap)
|
|
{
|
|
WCHAR SymLinkBuffer[0x1000];
|
|
UNICODE_STRING GlobalString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE hDirectory = 0;
|
|
NTSTATUS Status;
|
|
ULONG ReturnLength = 0;
|
|
ULONG BufferLength = 0x4000;
|
|
ULONG Context;
|
|
POBJECT_DIRECTORY_INFORMATION QueryBuffer;
|
|
HANDLE hSymLink;
|
|
UNICODE_STRING LinkTarget;
|
|
|
|
/* Initialize the Global String */
|
|
RtlInitUnicodeString(&GlobalString, GLOBAL_ROOT);
|
|
|
|
/* Initialize the Object Attributes */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&GlobalString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
/* Open the directory */
|
|
Status = NtOpenDirectoryObject(&hDirectory,
|
|
DIRECTORY_QUERY,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Allocate memory */
|
|
QueryBuffer = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, 0x4000);
|
|
if (!QueryBuffer) return STATUS_NO_MEMORY;
|
|
|
|
/* Start query loop */
|
|
while (TRUE)
|
|
{
|
|
/* Query the Directory */
|
|
Status = NtQueryDirectoryObject(hDirectory,
|
|
QueryBuffer,
|
|
BufferLength,
|
|
FALSE,
|
|
FALSE,
|
|
&Context,
|
|
&ReturnLength);
|
|
|
|
/* Check for the status */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Make sure it has a name */
|
|
if (!QueryBuffer->Name.Buffer[0]) continue;
|
|
|
|
/* Check if it's actually a symbolic link */
|
|
if (wcscmp(QueryBuffer->TypeName.Buffer, SYMLINK_NAME))
|
|
{
|
|
/* It is, open it */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&QueryBuffer->Name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
hDirectory);
|
|
Status = NtOpenSymbolicLinkObject(&hSymLink,
|
|
SYMBOLIC_LINK_QUERY,
|
|
&ObjectAttributes);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Setup the Target String */
|
|
LinkTarget.Length = 0;
|
|
LinkTarget.MaximumLength = sizeof(SymLinkBuffer);
|
|
LinkTarget.Buffer = SymLinkBuffer;
|
|
|
|
/* Query the target */
|
|
Status = NtQuerySymbolicLinkObject(hSymLink,
|
|
&LinkTarget,
|
|
&ReturnLength);
|
|
|
|
/* Close the handle */
|
|
NtClose(hSymLink);
|
|
|
|
}
|
|
}
|
|
}
|
|
/* FIXME: Loop never ends! */
|
|
}
|
|
}
|
|
|
|
/*++
|
|
* @name CsrLoadServerDllFromCommandLine
|
|
*
|
|
* The CsrLoadServerDllFromCommandLine routine loads a Server DLL from the
|
|
* CSRSS command-line in the registry.
|
|
*
|
|
* @param KeyValue
|
|
* Pointer to the specially formatted string for this Server DLL.
|
|
*
|
|
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
|
|
* othwerwise.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
NTAPI
|
|
CsrLoadServerDllFromCommandLine(PCHAR KeyValue)
|
|
{
|
|
PCHAR EntryPoint = NULL;
|
|
ULONG DllIndex = 0;
|
|
PCHAR ServerString = KeyValue;
|
|
NTSTATUS Status;
|
|
|
|
/* Loop the command line */
|
|
while (*ServerString)
|
|
{
|
|
/* Check for the Entry Point */
|
|
if ((*ServerString == ':') && (!EntryPoint))
|
|
{
|
|
/* Found it. Add a nullchar and save it */
|
|
*ServerString++ = '\0';
|
|
EntryPoint = ServerString;
|
|
}
|
|
|
|
/* Check for the Dll Index */
|
|
if (*ServerString++ == ',')
|
|
{
|
|
/* Convert it to a ULONG */
|
|
Status = RtlCharToInteger(ServerString, 10, &DllIndex);
|
|
|
|
/* Add a null char if it was valid */
|
|
if (NT_SUCCESS(Status)) ServerString[-1] = '\0';
|
|
|
|
/* We're done here */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* We've got the name, entrypoint and index, load it */
|
|
return CsrLoadServerDll(KeyValue, EntryPoint, DllIndex);
|
|
}
|
|
|
|
/*++
|
|
* @name CsrpParseCommandLine
|
|
*
|
|
* The CsrpParseCommandLine routine parses the CSRSS command-line in the
|
|
* registry and performs operations for each entry found.
|
|
*
|
|
* @param ArgumentCount
|
|
* Number of arguments on the command line.
|
|
*
|
|
* @param Arguments
|
|
* Array of arguments.
|
|
*
|
|
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
|
|
* othwerwise.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
FASTCALL
|
|
CsrpParseCommandLine(IN ULONG ArgumentCount,
|
|
IN PCHAR Arguments[])
|
|
{
|
|
NTSTATUS Status;
|
|
PCHAR ParameterName = NULL;
|
|
PCHAR ParameterValue = NULL;
|
|
ULONG i;
|
|
|
|
/* Set the Defaults */
|
|
CsrTotalPerProcessDataLength = 0;
|
|
CsrObjectDirectory = 0;
|
|
CsrMaxApiRequestThreads = 16;
|
|
|
|
/* Save our Session ID, and create a Directory for it */
|
|
SessionId = NtCurrentPeb()->SessionId;
|
|
Status = CsrCreateSessionObjectDirectory(SessionId);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSS: CsrCreateSessionObjectDirectory failed (%lx)\n",
|
|
Status);
|
|
|
|
/* It's not fatal if the SID is 0 */
|
|
if (SessionId != 0) return Status;
|
|
}
|
|
|
|
/* Loop through every argument */
|
|
for (i = 1; i < ArgumentCount; i++)
|
|
{
|
|
/* Split Name and Value */
|
|
ParameterName = Arguments[i];
|
|
ParameterValue = strchr(ParameterName, L'=');
|
|
*ParameterValue++ = '\0';
|
|
DPRINT("Name=%S, Value=%S\n", ParameterName, ParameterValue);
|
|
|
|
/* Check for Object Directory */
|
|
if (!_stricmp(ParameterName, "ObjectDirectory"))
|
|
{
|
|
CsrCreateObjectDirectory(ParameterValue);
|
|
}
|
|
else if(!_stricmp(ParameterName, "SubSystemType"))
|
|
{
|
|
/* Ignored */
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else if (!_stricmp(ParameterName, "MaxRequestThreads"))
|
|
{
|
|
Status = RtlCharToInteger(ParameterValue,
|
|
0,
|
|
&CsrMaxApiRequestThreads);
|
|
}
|
|
else if (!_stricmp(ParameterName, "RequestThreads"))
|
|
{
|
|
/* Ignored */
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else if (!_stricmp(ParameterName, "ProfileControl"))
|
|
{
|
|
CsrProfileControl = (!_stricmp(ParameterValue, "On")) ? TRUE : FALSE;
|
|
}
|
|
else if (!_stricmp(ParameterName, "SharedSection"))
|
|
{
|
|
/* Craete the Section */
|
|
Status = CsrSrvCreateSharedSection(ParameterValue);
|
|
|
|
/* Load us */
|
|
Status = CsrLoadServerDll("CSRSS", NULL, CSR_SRV_SERVER);
|
|
}
|
|
else if (!_stricmp(ParameterName, "ServerDLL"))
|
|
{
|
|
/* Parse the Command-Line and load this DLL */
|
|
Status = CsrLoadServerDllFromCommandLine(ParameterValue);
|
|
}
|
|
else if (!_stricmp(ParameterName, "Windows"))
|
|
{
|
|
/* Ignored */
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Invalid parameter on the command line */
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
/* Return status */
|
|
return Status;
|
|
}
|
|
|
|
/*++
|
|
* @name CsrCreateObjectDirectory
|
|
*
|
|
* The CsrCreateObjectDirectory creates the Object Directory on the CSRSS
|
|
* command-line from the registry.
|
|
*
|
|
* @param ObjectDirectory
|
|
* Pointer to the name of the Object Directory to create.
|
|
*
|
|
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
|
|
* othwerwise.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
NTAPI
|
|
CsrCreateObjectDirectory(IN PCHAR ObjectDirectory)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ANSI_STRING TempString;
|
|
OBJECT_ATTRIBUTES DirectoryAttributes;
|
|
|
|
DPRINT("CSRSRV:%s(%s) called\n", __FUNCTION__, ObjectDirectory);
|
|
|
|
/* Convert the parameter to our Global Unicode name */
|
|
RtlInitAnsiString(&TempString, ObjectDirectory);
|
|
Status = RtlAnsiStringToUnicodeString(&CsrDirectoryName, &TempString, TRUE);
|
|
|
|
/* Initialize the attributes for the Directory */
|
|
InitializeObjectAttributes(&DirectoryAttributes,
|
|
&CsrDirectoryName,
|
|
OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
/* Create it */
|
|
Status = NtCreateDirectoryObject(&CsrObjectDirectory,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&DirectoryAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSRV:%s: fatal: NtCreateDirectoryObject failed (Status=0x%08lx)\n",
|
|
__FUNCTION__, Status);
|
|
}
|
|
|
|
/* Set the Security */
|
|
Status = CsrSetDirectorySecurity(CsrObjectDirectory);
|
|
|
|
/* Return */
|
|
return Status;
|
|
}
|
|
|
|
/*++
|
|
* @name CsrCreateLocalSystemSD
|
|
*
|
|
* The CsrCreateLocalSystemSD routine creates a Security Descriptor for
|
|
* the local account with PORT_ALL_ACCESS.
|
|
*
|
|
* @param LocalSystemSd
|
|
* Pointer to a pointer to the security descriptor to create.
|
|
*
|
|
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
|
|
* othwerwise.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
NTAPI
|
|
CsrCreateLocalSystemSD(OUT PSECURITY_DESCRIPTOR *LocalSystemSd)
|
|
{
|
|
SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
|
|
PSID SystemSid;
|
|
ULONG SidLength;
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
|
PACL Dacl;
|
|
NTSTATUS Status;
|
|
|
|
/* Initialize the System SID */
|
|
RtlAllocateAndInitializeSid(&NtSidAuthority,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&SystemSid);
|
|
|
|
/* Get the length of the SID */
|
|
SidLength = RtlLengthSid(SystemSid);
|
|
|
|
/* Allocate a buffer for the Security Descriptor, with SID and DACL */
|
|
SecurityDescriptor = RtlAllocateHeap(CsrHeap,
|
|
0,
|
|
SECURITY_DESCRIPTOR_MIN_LENGTH +
|
|
sizeof(ACL) + SidLength +
|
|
sizeof(ACCESS_ALLOWED_ACE));
|
|
|
|
/* Set the pointer to the DACL */
|
|
Dacl = (PACL)((ULONG_PTR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
|
|
/* Now create the SD itself */
|
|
Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Fail */
|
|
RtlFreeHeap(CsrHeap, 0, SecurityDescriptor);
|
|
return Status;
|
|
}
|
|
|
|
/* Create the DACL for it*/
|
|
RtlCreateAcl(Dacl,
|
|
sizeof(ACL) + SidLength + sizeof(ACCESS_ALLOWED_ACE),
|
|
ACL_REVISION2);
|
|
|
|
/* Create the ACE */
|
|
Status = RtlAddAccessAllowedAce(Dacl,
|
|
ACL_REVISION,
|
|
PORT_ALL_ACCESS,
|
|
SystemSid);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Fail */
|
|
RtlFreeHeap(CsrHeap, 0, SecurityDescriptor);
|
|
return Status;
|
|
}
|
|
|
|
/* Clear the DACL in the SD */
|
|
Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
|
|
TRUE,
|
|
Dacl,
|
|
FALSE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Fail */
|
|
RtlFreeHeap(CsrHeap, 0, SecurityDescriptor);
|
|
return Status;
|
|
}
|
|
|
|
/* Free the SID and return*/
|
|
RtlFreeSid(SystemSid);
|
|
*LocalSystemSd = SecurityDescriptor;
|
|
return Status;
|
|
}
|
|
|
|
/*++
|
|
* @name CsrGetDosDevicesSd
|
|
*
|
|
* The CsrGetDosDevicesSd creates a security descriptor for the DOS Devices
|
|
* Object Directory.
|
|
*
|
|
* @param DosDevicesSd
|
|
* Pointer to the Security Descriptor to return.
|
|
*
|
|
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
|
|
* othwerwise.
|
|
*
|
|
* @remarks Depending on the DOS Devices Protection Mode (set in the registry),
|
|
* regular users may or may not have full access to the directory.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
NTAPI
|
|
CsrGetDosDevicesSd(OUT PSECURITY_DESCRIPTOR DosDevicesSd)
|
|
{
|
|
SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
|
|
SID_IDENTIFIER_AUTHORITY CreatorAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
|
|
SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
|
|
PSID WorldSid, CreatorSid, AdminSid, SystemSid;
|
|
UCHAR KeyValueBuffer[0x40];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
|
|
UNICODE_STRING KeyName;
|
|
ULONG ProtectionMode = 0;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PACL Dacl;
|
|
PACCESS_ALLOWED_ACE Ace;
|
|
HANDLE hKey;
|
|
NTSTATUS Status;
|
|
ULONG ResultLength, SidLength;
|
|
|
|
/* Create the SD */
|
|
RtlCreateSecurityDescriptor(DosDevicesSd, SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
/* Initialize the System SID */
|
|
RtlAllocateAndInitializeSid(&NtSidAuthority,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&SystemSid);
|
|
|
|
/* Initialize the World SID */
|
|
RtlAllocateAndInitializeSid(&WorldAuthority,
|
|
1,
|
|
SECURITY_WORLD_RID,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&WorldSid);
|
|
|
|
/* Initialize the Admin SID */
|
|
RtlAllocateAndInitializeSid(&NtSidAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&AdminSid);
|
|
|
|
/* Initialize the Creator SID */
|
|
RtlAllocateAndInitializeSid(&CreatorAuthority,
|
|
1,
|
|
SECURITY_CREATOR_OWNER_RID,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&CreatorSid);
|
|
|
|
/* Open the Session Manager Key */
|
|
RtlInitUnicodeString(&KeyName, SM_REG_KEY);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
if (NT_SUCCESS(Status = NtOpenKey(&hKey,
|
|
KEY_READ,
|
|
&ObjectAttributes)))
|
|
{
|
|
/* Read the ProtectionMode. See http://support.microsoft.com/kb/q218473/ */
|
|
RtlInitUnicodeString(&KeyName, L"ProtectionMode");
|
|
Status = NtQueryValueKey(hKey,
|
|
&KeyName,
|
|
KeyValuePartialInformation,
|
|
KeyValueBuffer,
|
|
sizeof(KeyValueBuffer),
|
|
&ResultLength);
|
|
|
|
/* Make sure it's what we expect it to be */
|
|
KeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
|
|
if ((KeyValuePartialInfo->Type == REG_DWORD) &&
|
|
(*(PULONG)KeyValuePartialInfo->Data != 0))
|
|
{
|
|
/* Save the Protection Mode */
|
|
ProtectionMode = *(PULONG)KeyValuePartialInfo->Data;
|
|
}
|
|
|
|
/* Close the handle */
|
|
NtClose(hKey);
|
|
}
|
|
|
|
/* Check the Protection Mode */
|
|
if (ProtectionMode & 3)
|
|
{
|
|
/* Calculate SID Lengths */
|
|
SidLength = RtlLengthSid(CreatorSid) + RtlLengthSid(SystemSid) +
|
|
RtlLengthSid(AdminSid);
|
|
|
|
/* Allocate memory for the DACL */
|
|
Dacl = RtlAllocateHeap(CsrHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) +
|
|
SidLength);
|
|
|
|
/* Create it */
|
|
Status = RtlCreateAcl(Dacl,
|
|
sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) +
|
|
SidLength,
|
|
ACL_REVISION2);
|
|
|
|
/* Give full access to the System */
|
|
Status = RtlAddAccessAllowedAce(Dacl,
|
|
ACL_REVISION,
|
|
GENERIC_ALL,
|
|
SystemSid);
|
|
|
|
/* Get the ACE back */
|
|
Status = RtlGetAce(Dacl, 0, (PVOID*)&Ace);
|
|
|
|
/* Add some flags to it for the Admin SID */
|
|
Ace->Header.AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
|
|
|
|
/* Add the ACE to the Admin SID */
|
|
Status = RtlAddAccessAllowedAce(Dacl,
|
|
ACL_REVISION,
|
|
GENERIC_ALL,
|
|
AdminSid);
|
|
|
|
/* Get the ACE back */
|
|
Status = RtlGetAce(Dacl, 1, (PVOID*)&Ace);
|
|
|
|
/* Add some flags to it for the Creator SID */
|
|
Ace->Header.AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
|
|
|
|
/* Add the ACE to the Admin SID */
|
|
Status = RtlAddAccessAllowedAce(Dacl,
|
|
ACL_REVISION,
|
|
GENERIC_ALL,
|
|
CreatorSid);
|
|
|
|
/* Get the ACE back */
|
|
Status = RtlGetAce(Dacl, 2, (PVOID*)&Ace);
|
|
|
|
/* Add some flags to it for the SD */
|
|
Ace->Header.AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
|
|
INHERIT_ONLY_ACE);
|
|
|
|
/* Set this DACL with the SD */
|
|
Status = RtlSetDaclSecurityDescriptor(DosDevicesSd,
|
|
TRUE,
|
|
Dacl,
|
|
FALSE);
|
|
}
|
|
else
|
|
{
|
|
/* Calculate SID Lengths */
|
|
SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(SystemSid);
|
|
|
|
/* Allocate memory for the DACL */
|
|
Dacl = RtlAllocateHeap(CsrHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) +
|
|
SidLength);
|
|
|
|
/* Create it */
|
|
Status = RtlCreateAcl(Dacl,
|
|
sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) +
|
|
SidLength,
|
|
ACL_REVISION2);
|
|
|
|
/* Give RWE access to the World */
|
|
Status = RtlAddAccessAllowedAce(Dacl,
|
|
ACL_REVISION,
|
|
GENERIC_READ | GENERIC_WRITE |
|
|
GENERIC_EXECUTE,
|
|
WorldSid);
|
|
|
|
/* Give full access to the System */
|
|
Status = RtlAddAccessAllowedAce(Dacl,
|
|
ACL_REVISION,
|
|
GENERIC_ALL,
|
|
SystemSid);
|
|
|
|
/* Give full access to the World */
|
|
Status = RtlAddAccessAllowedAce(Dacl,
|
|
ACL_REVISION,
|
|
GENERIC_ALL,
|
|
WorldSid);
|
|
|
|
/* Get the ACE back */
|
|
Status = RtlGetAce(Dacl, 2, (PVOID*)&Ace);
|
|
|
|
/* Add some flags to it for the SD */
|
|
Ace->Header.AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
|
|
INHERIT_ONLY_ACE);
|
|
|
|
/* Set this DACL with the SD */
|
|
Status = RtlSetDaclSecurityDescriptor(DosDevicesSd,
|
|
TRUE,
|
|
Dacl,
|
|
FALSE);
|
|
}
|
|
|
|
/* FIXME: failure cases! Fail: */
|
|
/* Free the memory */
|
|
RtlFreeHeap(CsrHeap, 0, Dacl);
|
|
|
|
/* FIXME: semi-failure cases! Quickie: */
|
|
/* Free the SIDs */
|
|
RtlFreeSid(SystemSid);
|
|
RtlFreeSid(WorldSid);
|
|
RtlFreeSid(AdminSid);
|
|
RtlFreeSid(CreatorSid);
|
|
|
|
/* Return */
|
|
return Status;
|
|
}
|
|
|
|
/*++
|
|
* @name CsrFreeDosDevicesSd
|
|
*
|
|
* The CsrFreeDosDevicesSd frees the security descriptor that was created
|
|
* by CsrGetDosDevicesSd
|
|
*
|
|
* @param DosDevicesSd
|
|
* Pointer to the security descriptor to free.
|
|
|
|
* @return None.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
VOID
|
|
NTAPI
|
|
CsrFreeDosDevicesSd(IN PSECURITY_DESCRIPTOR DosDevicesSd)
|
|
{
|
|
PACL Dacl;
|
|
BOOLEAN Present, Default;
|
|
NTSTATUS Status;
|
|
|
|
/* Get the DACL corresponding to this SD */
|
|
Status = RtlGetDaclSecurityDescriptor(DosDevicesSd,
|
|
&Present,
|
|
&Dacl,
|
|
&Default);
|
|
|
|
/* Free it */
|
|
if (NT_SUCCESS(Status) && Dacl) RtlFreeHeap(CsrHeap, 0, Dacl);
|
|
}
|
|
|
|
/*++
|
|
* @name CsrCreateSessionObjectDirectory
|
|
*
|
|
* The CsrCreateSessionObjectDirectory routine creates the BaseNamedObjects,
|
|
* Session and Dos Devices directories for the specified session.
|
|
*
|
|
* @param Session
|
|
* Session ID for which to create the directories.
|
|
*
|
|
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
|
|
* othwerwise.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
NTAPI
|
|
CsrCreateSessionObjectDirectory(IN ULONG Session)
|
|
{
|
|
WCHAR SessionBuffer[512];
|
|
WCHAR BnoBuffer[512];
|
|
UNICODE_STRING SessionString;
|
|
UNICODE_STRING BnoString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE BnoHandle;
|
|
SECURITY_DESCRIPTOR DosDevicesSd;
|
|
NTSTATUS Status;
|
|
|
|
/* Generate the Session BNOLINKS Directory */
|
|
swprintf(SessionBuffer, L"%ws\\BNOLINKS", SESSION_ROOT);
|
|
RtlInitUnicodeString(&SessionString, SessionBuffer);
|
|
|
|
/* Initialize the attributes for the Directory */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&SessionString,
|
|
OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
/* Create it */
|
|
Status = NtCreateDirectoryObject(&BNOLinksDirectory,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSRV:%s: fatal: NtCreateDirectoryObject failed (Status=0x%08lx)\n",
|
|
__FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Now add the Session ID */
|
|
swprintf(SessionBuffer, L"%ld", Session);
|
|
RtlInitUnicodeString(&SessionString, SessionBuffer);
|
|
|
|
/* Check if this is the first Session */
|
|
if (Session)
|
|
{
|
|
/* Not the first, so the name will be slighly more complex */
|
|
swprintf(BnoBuffer, L"%ws\\%ld\\BaseNamedObjects", SESSION_ROOT, Session);
|
|
}
|
|
else
|
|
{
|
|
/* Use the direct name */
|
|
RtlCopyMemory(BnoBuffer, L"\\BaseNamedObjects", 36);
|
|
}
|
|
|
|
/* Create the Unicode String for the BNO SymLink */
|
|
RtlInitUnicodeString(&BnoString, BnoBuffer);
|
|
|
|
/* Initialize the attributes for the SymLink */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&SessionString,
|
|
OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
BNOLinksDirectory,
|
|
NULL);
|
|
|
|
/* Create it */
|
|
Status = NtCreateSymbolicLinkObject(&BnoHandle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
&BnoString);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSRV:%s: fatal: NtCreateSymbolicLinkObject failed (Status=0x%08lx)\n",
|
|
__FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Create the \DosDevices Security Descriptor */
|
|
CsrGetDosDevicesSd(&DosDevicesSd);
|
|
|
|
/* Now create a directory for this session */
|
|
swprintf(SessionBuffer, L"%ws\\%ld", SESSION_ROOT, Session);
|
|
RtlInitUnicodeString(&SessionString, SessionBuffer);
|
|
|
|
/* Initialize the attributes for the Directory */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&SessionString,
|
|
OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
0,
|
|
&DosDevicesSd);
|
|
|
|
/* Create it */
|
|
Status = NtCreateDirectoryObject(&SessionObjectDirectory,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSRV:%s: fatal: NtCreateDirectoryObject failed (Status=0x%08lx)\n",
|
|
__FUNCTION__, Status);
|
|
/* Release the Security Descriptor */
|
|
CsrFreeDosDevicesSd(&DosDevicesSd);
|
|
return Status;
|
|
}
|
|
|
|
/* Next, create a directory for this session's DOS Devices */
|
|
/* Now create a directory for this session */
|
|
RtlInitUnicodeString(&SessionString, L"DosDevices");
|
|
|
|
/* Initialize the attributes for the Directory */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&SessionString,
|
|
OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
0,
|
|
&DosDevicesSd);
|
|
|
|
/* Create it */
|
|
Status = NtCreateDirectoryObject(&DosDevicesDirectory,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSRV:%s: fatal: NtCreateDirectoryObject failed (Status=0x%08lx)\n",
|
|
__FUNCTION__, Status);
|
|
}
|
|
|
|
/* Release the Security Descriptor */
|
|
CsrFreeDosDevicesSd(&DosDevicesSd);
|
|
|
|
/* Return */
|
|
return Status;
|
|
}
|
|
|
|
/*++
|
|
* @name CsrSetProcessSecurity
|
|
*
|
|
* The CsrSetProcessSecurity routine protects access to the CSRSS process
|
|
* from unauthorized tampering.
|
|
*
|
|
* @param None.
|
|
*
|
|
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
|
|
* othwerwise.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
NTAPI
|
|
CsrSetProcessSecurity(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE hToken;
|
|
ULONG ReturnLength;
|
|
PTOKEN_USER TokenUserInformation;
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
|
PACL Dacl;
|
|
|
|
/* Open our token */
|
|
Status = NtOpenProcessToken(NtCurrentProcess(),
|
|
TOKEN_QUERY,
|
|
&hToken);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Get the Token User Length */
|
|
NtQueryInformationToken(hToken,
|
|
TokenUser,
|
|
NULL,
|
|
0,
|
|
&ReturnLength);
|
|
|
|
/* Allocate space for it */
|
|
TokenUserInformation = RtlAllocateHeap(CsrHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
ReturnLength);
|
|
|
|
/* Now query the data */
|
|
Status = NtQueryInformationToken(hToken,
|
|
TokenUser,
|
|
TokenUserInformation,
|
|
ReturnLength,
|
|
&ReturnLength);
|
|
|
|
/* Close the handle */
|
|
NtClose(hToken);
|
|
|
|
/* Make sure that we got the data */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* FAil */
|
|
RtlFreeHeap(CsrHeap, 0, TokenUserInformation);
|
|
return Status;
|
|
}
|
|
|
|
/* Now check the SID Length */
|
|
ReturnLength = RtlLengthSid(TokenUserInformation->User.Sid);
|
|
|
|
/* Allocate a buffer for the Security Descriptor, with SID and DACL */
|
|
SecurityDescriptor = RtlAllocateHeap(CsrHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
SECURITY_DESCRIPTOR_MIN_LENGTH +
|
|
sizeof(ACL) + ReturnLength +
|
|
sizeof(ACCESS_ALLOWED_ACE));
|
|
|
|
/* Set the pointer to the DACL */
|
|
Dacl = (PACL)((ULONG_PTR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
|
|
/* Now create the SD itself */
|
|
Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Fail */
|
|
RtlFreeHeap(CsrHeap, 0, SecurityDescriptor);
|
|
RtlFreeHeap(CsrHeap, 0, TokenUserInformation);
|
|
return Status;
|
|
}
|
|
|
|
/* Create the DACL for it*/
|
|
RtlCreateAcl(Dacl,
|
|
sizeof(ACL) + ReturnLength + sizeof(ACCESS_ALLOWED_ACE),
|
|
ACL_REVISION2);
|
|
|
|
/* Create the ACE */
|
|
Status = RtlAddAccessAllowedAce(Dacl,
|
|
ACL_REVISION,
|
|
PROCESS_VM_READ | PROCESS_VM_WRITE |
|
|
PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE |
|
|
PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME |
|
|
PROCESS_QUERY_INFORMATION | READ_CONTROL,
|
|
TokenUserInformation->User.Sid);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Fail */
|
|
RtlFreeHeap(CsrHeap, 0, SecurityDescriptor);
|
|
RtlFreeHeap(CsrHeap, 0, TokenUserInformation);
|
|
return Status;
|
|
}
|
|
|
|
/* Clear the DACL in the SD */
|
|
Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
|
|
TRUE,
|
|
Dacl,
|
|
FALSE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Fail */
|
|
RtlFreeHeap(CsrHeap, 0, SecurityDescriptor);
|
|
RtlFreeHeap(CsrHeap, 0, TokenUserInformation);
|
|
return Status;
|
|
}
|
|
|
|
/* Write the SD into the Process */
|
|
Status = NtSetSecurityObject(NtCurrentProcess(),
|
|
DACL_SECURITY_INFORMATION,
|
|
SecurityDescriptor);
|
|
|
|
/* Free the memory and return */
|
|
RtlFreeHeap(CsrHeap, 0, SecurityDescriptor);
|
|
RtlFreeHeap(CsrHeap, 0, TokenUserInformation);
|
|
return Status;
|
|
}
|
|
|
|
/*++
|
|
* @name CsrSetDirectorySecurity
|
|
*
|
|
* The CsrSetDirectorySecurity routine sets the security descriptor for the
|
|
* specified Object Directory.
|
|
*
|
|
* @param ObjectDirectory
|
|
* Handle fo the Object Directory to protect.
|
|
*
|
|
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
|
|
* othwerwise.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
NTAPI
|
|
CsrSetDirectorySecurity(IN HANDLE ObjectDirectory)
|
|
{
|
|
/* FIXME: Implement */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
/*++
|
|
* @name CsrServerInitialization
|
|
* @implemented NT4
|
|
*
|
|
* The CsrServerInitialization routine is the native (not Server) entrypoint
|
|
* of this Server DLL. It serves as the entrypoint for csrss.
|
|
*
|
|
* @param ArgumentCount
|
|
* Number of arguments on the command line.
|
|
*
|
|
* @param Arguments
|
|
* Array of arguments from the command line.
|
|
*
|
|
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
|
|
* othwerwise.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
NTAPI
|
|
CsrServerInitialization(ULONG ArgumentCount,
|
|
PCHAR Arguments[])
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG i = 0;
|
|
PVOID ProcessData;
|
|
PCSR_SERVER_DLL ServerDll;
|
|
|
|
DPRINT("CSRSRV: %s called\n", __FUNCTION__);
|
|
|
|
/* Create the Init Event */
|
|
Status = NtCreateEvent(&CsrInitializationEvent,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
/* Cache System Basic Information so we don't always request it */
|
|
Status = NtQuerySystemInformation(SystemBasicInformation,
|
|
&CsrNtSysInfo,
|
|
sizeof(SYSTEM_BASIC_INFORMATION),
|
|
NULL);
|
|
|
|
/* Save our Heap */
|
|
CsrHeap = RtlGetProcessHeap();
|
|
|
|
/* Set our Security Descriptor to protect the process */
|
|
CsrSetProcessSecurity();
|
|
|
|
/* Set up Session Support */
|
|
Status = CsrInitializeNtSessions();
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSRV:%s: CsrInitializeSessions failed (Status=%08lx)\n",
|
|
__FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Set up Process Support */
|
|
Status = CsrInitializeProcesses();
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSRV:%s: CsrInitializeProcesses failed (Status=%08lx)\n",
|
|
__FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Parse the command line */
|
|
CsrpParseCommandLine(ArgumentCount, Arguments);
|
|
|
|
/* All Server DLLs are now loaded, allocate a heap for the Root Process */
|
|
ProcessData = RtlAllocateHeap(CsrHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
CsrTotalPerProcessDataLength);
|
|
|
|
/*
|
|
* Our Root Process was never officially initalized, so write the data
|
|
* for each Server DLL manually.
|
|
*/
|
|
for(i = 0; i < CSR_SERVER_DLL_MAX; i++)
|
|
{
|
|
/* Get the current Server */
|
|
ServerDll = CsrLoadedServerDll[i];
|
|
|
|
/* Is it loaded, and does it have per process data? */
|
|
if (ServerDll && ServerDll->SizeOfProcessData)
|
|
{
|
|
/* It does, give it part of our allocated heap */
|
|
CsrRootProcess->ServerData[i] = ProcessData;
|
|
|
|
/* Move to the next heap position */
|
|
ProcessData = (PVOID)((ULONG_PTR)ProcessData +
|
|
ServerDll->SizeOfProcessData);
|
|
}
|
|
else
|
|
{
|
|
/* Nothing for this Server DLL */
|
|
CsrRootProcess->ServerData[i] = NULL;
|
|
}
|
|
}
|
|
|
|
/* Now initialize the Root Process manually as well */
|
|
for(i = 0; i < CSR_SERVER_DLL_MAX; i++)
|
|
{
|
|
/* Get the current Server */
|
|
ServerDll = CsrLoadedServerDll[i];
|
|
|
|
/* Is it loaded, and does it a callback for new processes? */
|
|
if (ServerDll && ServerDll->NewProcessCallback)
|
|
{
|
|
/* Call the callback */
|
|
(*ServerDll->NewProcessCallback)(NULL, CsrRootProcess);
|
|
}
|
|
}
|
|
|
|
/* Now initialize our API Port */
|
|
Status = CsrApiPortInitialize();
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSRV:%s: CsrApiPortInitialize failed (Status=%08lx)\n",
|
|
__FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Initialize the API Port for SM communication */
|
|
Status = CsrSbApiPortInitialize();
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSRV:%s: CsrSbApiPortInitialize failed (Status=%08lx)\n",
|
|
__FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
|
|
/* We're all set! Connect to SM! */
|
|
Status = SmConnectToSm(&CsrSbApiPortName,
|
|
CsrSbApiPort,
|
|
IMAGE_SUBSYSTEM_WINDOWS_GUI,
|
|
&CsrSmApiPort);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CSRSRV:%s: SmConnectToSm failed (Status=%08lx)\n",
|
|
__FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Finito! Signal the event */
|
|
NtSetEvent(CsrInitializationEvent, NULL);
|
|
NtClose(CsrInitializationEvent);
|
|
|
|
/* Have us handle Hard Errors */
|
|
NtSetDefaultHardErrorPort(CsrApiPort);
|
|
|
|
/* Return status */
|
|
return Status;
|
|
}
|
|
|
|
/*++
|
|
* @name CsrPopulateDosDevices
|
|
* @implemented NT5.1
|
|
*
|
|
* The CsrPopulateDosDevices routine uses the DOS Device Map from the Kernel
|
|
* to populate the Dos Devices Object Directory for the session.
|
|
*
|
|
* @param None.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
VOID
|
|
NTAPI
|
|
CsrPopulateDosDevices(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
PROCESS_DEVICEMAP_INFORMATION OldDeviceMap;
|
|
PROCESS_DEVICEMAP_INFORMATION NewDeviceMap;
|
|
|
|
/* Query the Device Map */
|
|
Status = NtQueryInformationProcess(NtCurrentProcess(),
|
|
ProcessDeviceMap,
|
|
&OldDeviceMap.Query,
|
|
sizeof(PROCESS_DEVICEMAP_INFORMATION),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status)) return;
|
|
|
|
/* Set the new one */
|
|
NewDeviceMap.Set.DirectoryHandle = DosDevicesDirectory;
|
|
Status = NtSetInformationProcess(NtCurrentProcess(),
|
|
ProcessDeviceMap,
|
|
&NewDeviceMap,
|
|
sizeof(ULONG));
|
|
if (!NT_SUCCESS(Status)) return;
|
|
|
|
/* Populate the Directory */
|
|
CsrPopulateDosDevicesDirectory(DosDevicesDirectory, &OldDeviceMap);
|
|
}
|
|
|
|
BOOL
|
|
NTAPI
|
|
DllMainCRTStartup(HANDLE hDll,
|
|
DWORD dwReason,
|
|
LPVOID lpReserved)
|
|
{
|
|
/* We don't do much */
|
|
UNREFERENCED_PARAMETER(hDll);
|
|
UNREFERENCED_PARAMETER(dwReason);
|
|
UNREFERENCED_PARAMETER(lpReserved);
|
|
return TRUE;
|
|
}
|
|
|
|
/* EOF */
|