reactos/subsystems/csr/csrsrv/init.c
Timo Kreuzer 6afbc8f483 Hopefully create a branch and not destroy the svn repository.
svn path=/branches/reactos-yarotows/; revision=45219
2010-01-23 23:25:04 +00:00

1237 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 */