/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: subsys/csrss/win32csr/file.c * PURPOSE: File handling * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org) * NOTE: Belongs to basesrv.dll */ /* INCLUDES ******************************************************************/ #include #define NDEBUG #include #include "file.h" /* GLOBALS *******************************************************************/ typedef BOOL (WINAPI *PUSER_SOUND_SENTRY)(VOID); BOOL WINAPI FirstSoundSentry(VOID); UINT CsrGetTempFileUnique; LIST_ENTRY DosDeviceHistory; RTL_CRITICAL_SECTION Win32CsrDefineDosDeviceCritSec; PUSER_SOUND_SENTRY _UserSoundSentry = FirstSoundSentry; /* FUNCTIONS *****************************************************************/ BOOL WINAPI FailSoundSentry(VOID) { /* In case the function can't be found/is unimplemented */ return FALSE; } BOOL WINAPI FirstSoundSentry(VOID) { UNICODE_STRING DllString = RTL_CONSTANT_STRING(L"winsrv"); STRING FuncString = RTL_CONSTANT_STRING("_UserSoundSentry"); HANDLE DllHandle; NTSTATUS Status; PUSER_SOUND_SENTRY NewSoundSentry = FailSoundSentry; /* Load winsrv manually */ Status = LdrGetDllHandle(NULL, NULL, &DllString, &DllHandle); if (NT_SUCCESS(Status)) { /* If it was found, get SoundSentry export */ Status = LdrGetProcedureAddress(DllHandle, &FuncString, 0, (PVOID*)&NewSoundSentry); } /* Set it as the callback for the future, and call it */ _UserSoundSentry = NewSoundSentry; return _UserSoundSentry(); } CSR_API(CsrSoundSentry) { /* Call the API and see if it suceeds */ return _UserSoundSentry() ? STATUS_SUCCESS : STATUS_ACCESS_DENIED; } CSR_API(CsrGetTempFile) { DPRINT("CsrGetTempFile entered\n"); /* Return 16-bits ID */ Request->Data.GetTempFile.UniqueID = (++CsrGetTempFileUnique & 0xFFFF); DPRINT("Returning: %u\n", Request->Data.GetTempFile.UniqueID); return STATUS_SUCCESS; } CSR_API(CsrDefineDosDevice) { OBJECT_ATTRIBUTES ObjectAttributes; HANDLE LinkHandle = NULL; NTSTATUS Status; UNICODE_STRING DeviceName = {0}; UNICODE_STRING RequestDeviceName = {0}; UNICODE_STRING LinkTarget = {0}; PUNICODE_STRING RequestLinkTarget; ULONG Length; SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY}; PSECURITY_DESCRIPTOR SecurityDescriptor; PACL Dacl; PSID AdminSid; PSID SystemSid; PSID WorldSid; ULONG SidLength; PCSRSS_DOS_DEVICE_HISTORY_ENTRY HistoryEntry; PLIST_ENTRY Entry; PLIST_ENTRY ListHead; BOOLEAN Matched, AddHistory; DWORD dwFlags; PWSTR lpBuffer; DPRINT("CsrDefineDosDevice entered, Flags:%d, DeviceName:%wZ, TargetName:%wZ\n", Request->Data.DefineDosDeviceRequest.dwFlags, &Request->Data.DefineDosDeviceRequest.DeviceName, &Request->Data.DefineDosDeviceRequest.TargetName); Matched = AddHistory = FALSE; HistoryEntry = NULL; AdminSid = SystemSid = WorldSid = NULL; SecurityDescriptor = NULL; ListHead = &DosDeviceHistory; dwFlags = Request->Data.DefineDosDeviceRequest.dwFlags; /* Validate the flags */ if ( (dwFlags & 0xFFFFFFF0) || ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) && ! (dwFlags & DDD_REMOVE_DEFINITION)) ) { return STATUS_INVALID_PARAMETER; } Status = RtlEnterCriticalSection(&Win32CsrDefineDosDeviceCritSec); if (! NT_SUCCESS(Status)) { DPRINT1("RtlEnterCriticalSection() failed (Status %lx)\n", Status); return Status; } _SEH2_TRY { Status = RtlUpcaseUnicodeString(&RequestDeviceName, &Request->Data.DefineDosDeviceRequest.DeviceName, TRUE); if (! NT_SUCCESS(Status)) _SEH2_LEAVE; RequestLinkTarget = &Request->Data.DefineDosDeviceRequest.TargetName; lpBuffer = (PWSTR) RtlAllocateHeap(Win32CsrApiHeap, HEAP_ZERO_MEMORY, RequestDeviceName.MaximumLength + 5 * sizeof(WCHAR)); if (! lpBuffer) { DPRINT1("Failed to allocate memory\n"); Status = STATUS_NO_MEMORY; _SEH2_LEAVE; } swprintf(lpBuffer, L"\\??\\%wZ", &RequestDeviceName); RtlInitUnicodeString(&DeviceName, lpBuffer); InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenSymbolicLinkObject(&LinkHandle, DELETE | 0x1, &ObjectAttributes); if (NT_SUCCESS(Status)) { Status = NtQuerySymbolicLinkObject(LinkHandle, &LinkTarget, &Length); if (! NT_SUCCESS(Status) && Status == STATUS_BUFFER_TOO_SMALL) { LinkTarget.Length = 0; LinkTarget.MaximumLength = Length; LinkTarget.Buffer = (PWSTR) RtlAllocateHeap(Win32CsrApiHeap, HEAP_ZERO_MEMORY, Length); if (! LinkTarget.Buffer) { DPRINT1("Failed to allocate memory\n"); Status = STATUS_NO_MEMORY; _SEH2_LEAVE; } Status = NtQuerySymbolicLinkObject(LinkHandle, &LinkTarget, &Length); } if (! NT_SUCCESS(Status)) { DPRINT1("NtQuerySymbolicLinkObject(%wZ) failed (Status %lx)\n", &DeviceName, Status); _SEH2_LEAVE; } if ((dwFlags & DDD_REMOVE_DEFINITION)) { /* If no target name specified we remove the current symlink target */ if (RequestLinkTarget->Length == 0) Matched = TRUE; else { if (dwFlags & DDD_EXACT_MATCH_ON_REMOVE) Matched = ! RtlCompareUnicodeString(RequestLinkTarget, &LinkTarget, TRUE); else Matched = RtlPrefixUnicodeString(RequestLinkTarget, &LinkTarget, TRUE); } if (Matched && IsListEmpty(ListHead)) { /* Current symlink target macthed and there is nothing to revert to */ RequestLinkTarget = NULL; } else if (Matched && ! IsListEmpty(ListHead)) { /* Fetch the first history entry we come across for the device name */ /* This will become the current symlink target for the device name */ Matched = FALSE; Entry = ListHead->Flink; while (Entry != ListHead) { HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY) CONTAINING_RECORD(Entry, CSRSS_DOS_DEVICE_HISTORY_ENTRY, Entry); Matched = ! RtlCompareUnicodeString(&RequestDeviceName, &HistoryEntry->Device, FALSE); if (Matched) { RemoveEntryList(&HistoryEntry->Entry); RequestLinkTarget = &HistoryEntry->Target; break; } Entry = Entry->Flink; HistoryEntry = NULL; } /* Nothing to revert to so delete the symlink */ if (! Matched) RequestLinkTarget = NULL; } else if (! Matched) { /* Locate a previous symlink target as we did not get a hit earlier */ /* If we find one we need to remove it */ Entry = ListHead->Flink; while (Entry != ListHead) { HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY) CONTAINING_RECORD(Entry, CSRSS_DOS_DEVICE_HISTORY_ENTRY, Entry); Matched = ! RtlCompareUnicodeString(&RequestDeviceName, &HistoryEntry->Device, FALSE); if (! Matched) { HistoryEntry = NULL; Entry = Entry->Flink; continue; } Matched = FALSE; if (dwFlags & DDD_EXACT_MATCH_ON_REMOVE) { if (! RtlCompareUnicodeString(RequestLinkTarget, &HistoryEntry->Target, TRUE)) { Matched = TRUE; } } else if (RtlPrefixUnicodeString(RequestLinkTarget, &HistoryEntry->Target, TRUE)) { Matched = TRUE; } if (Matched) { RemoveEntryList(&HistoryEntry->Entry); break; } Entry = Entry->Flink; HistoryEntry = NULL; } /* Leave existing symlink as is */ if (! Matched) Status = STATUS_OBJECT_NAME_NOT_FOUND; else Status = STATUS_SUCCESS; _SEH2_LEAVE; } } else { AddHistory = TRUE; } Status = NtMakeTemporaryObject(LinkHandle); if (! NT_SUCCESS(Status)) { DPRINT1("NtMakeTemporaryObject(%wZ) failed (Status %lx)\n", &DeviceName, Status); _SEH2_LEAVE; } Status = NtClose(LinkHandle); LinkHandle = NULL; if (! NT_SUCCESS(Status)) { DPRINT1("NtClose(%wZ) failed (Status %lx)\n", &DeviceName, Status); _SEH2_LEAVE; } } /* Don't create symlink if we don't have a target */ if (! RequestLinkTarget || RequestLinkTarget->Length == 0) _SEH2_LEAVE; if (AddHistory) { HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY) RtlAllocateHeap(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_DOS_DEVICE_HISTORY_ENTRY)); if (! HistoryEntry) { DPRINT1("Failed to allocate memory\n"); Status = STATUS_NO_MEMORY; _SEH2_LEAVE; } HistoryEntry->Target.Buffer = RtlAllocateHeap(Win32CsrApiHeap, HEAP_ZERO_MEMORY, LinkTarget.Length); if (! HistoryEntry->Target.Buffer) { DPRINT1("Failed to allocate memory\n"); Status = STATUS_NO_MEMORY; _SEH2_LEAVE; } HistoryEntry->Target.Length = HistoryEntry->Target.MaximumLength = LinkTarget.Length; RtlCopyUnicodeString(&HistoryEntry->Target, &LinkTarget); HistoryEntry->Device.Buffer = RtlAllocateHeap(Win32CsrApiHeap, HEAP_ZERO_MEMORY, RequestDeviceName.Length); if (! HistoryEntry->Device.Buffer) { DPRINT1("Failed to allocate memory\n"); Status = STATUS_NO_MEMORY; _SEH2_LEAVE; } HistoryEntry->Device.Length = HistoryEntry->Device.MaximumLength = RequestDeviceName.Length; RtlCopyUnicodeString(&HistoryEntry->Device, &RequestDeviceName); /* Remember previous symlink target for this device */ InsertHeadList(ListHead, &HistoryEntry->Entry); HistoryEntry = NULL; } RtlAllocateAndInitializeSid(&WorldAuthority, 1, SECURITY_WORLD_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, &WorldSid); RtlAllocateAndInitializeSid(&SystemAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, &SystemSid); RtlAllocateAndInitializeSid(&SystemAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, &AdminSid); SidLength = RtlLengthSid(SystemSid) + RtlLengthSid(AdminSid) + RtlLengthSid(WorldSid); Length = sizeof(ACL) + SidLength + 3 * sizeof(ACCESS_ALLOWED_ACE); SecurityDescriptor = RtlAllocateHeap(Win32CsrApiHeap, 0, SECURITY_DESCRIPTOR_MIN_LENGTH + Length); if (! SecurityDescriptor) { DPRINT1("Failed to allocate memory\n"); Status = STATUS_NO_MEMORY; _SEH2_LEAVE; } Dacl = (PACL)((ULONG_PTR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); if (! NT_SUCCESS(Status)) { DPRINT1("RtlCreateSecurityDescriptor() failed (Status %lx)\n", Status); _SEH2_LEAVE; } Status = RtlCreateAcl(Dacl, Length, ACL_REVISION); if (! NT_SUCCESS(Status)) { DPRINT1("RtlCreateAcl() failed (Status %lx)\n", Status); _SEH2_LEAVE; } (void) RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, SystemSid); (void) RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, AdminSid); (void) RtlAddAccessAllowedAce(Dacl, ACL_REVISION, STANDARD_RIGHTS_READ, WorldSid); Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, Dacl, FALSE); if (! NT_SUCCESS(Status)) { DPRINT1("RtlSetDaclSecurityDescriptor() failed (Status %lx)\n", Status); _SEH2_LEAVE; } InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_CASE_INSENSITIVE, NULL, SecurityDescriptor); Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes, RequestLinkTarget); if (NT_SUCCESS(Status)) { Status = NtMakePermanentObject(LinkHandle); if (! NT_SUCCESS(Status)) { DPRINT1("NtMakePermanentObject(%wZ) failed (Status %lx)\n", &DeviceName, Status); } } else { DPRINT1("NtCreateSymbolicLinkObject(%wZ) failed (Status %lx)\n", &DeviceName, Status); } } _SEH2_FINALLY { (void) RtlLeaveCriticalSection(&Win32CsrDefineDosDeviceCritSec); if (DeviceName.Buffer) (void) RtlFreeHeap(Win32CsrApiHeap, 0, DeviceName.Buffer); if (LinkTarget.Buffer) (void) RtlFreeHeap(Win32CsrApiHeap, 0, LinkTarget.Buffer); if (SecurityDescriptor) (void) RtlFreeHeap(Win32CsrApiHeap, 0, SecurityDescriptor); if (LinkHandle) (void) NtClose(LinkHandle); if (SystemSid) (void) RtlFreeSid(SystemSid); if (AdminSid) (void) RtlFreeSid(AdminSid); if (WorldSid) (void) RtlFreeSid(WorldSid); RtlFreeUnicodeString(&RequestDeviceName); if (HistoryEntry) { if (HistoryEntry->Target.Buffer) (void) RtlFreeHeap(Win32CsrApiHeap, 0, HistoryEntry->Target.Buffer); if (HistoryEntry->Device.Buffer) (void) RtlFreeHeap(Win32CsrApiHeap, 0, HistoryEntry->Device.Buffer); (void) RtlFreeHeap(Win32CsrApiHeap, 0, HistoryEntry); } } _SEH2_END DPRINT("CsrDefineDosDevice Exit, Statux: 0x%x\n", Status); return Status; } void CsrCleanupDefineDosDevice(void) { PLIST_ENTRY Entry, ListHead; PCSRSS_DOS_DEVICE_HISTORY_ENTRY HistoryEntry; (void) RtlDeleteCriticalSection(&Win32CsrDefineDosDeviceCritSec); ListHead = &DosDeviceHistory; Entry = ListHead->Flink; while (Entry != ListHead) { HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY) CONTAINING_RECORD(Entry, CSRSS_DOS_DEVICE_HISTORY_ENTRY, Entry); Entry = Entry->Flink; if (HistoryEntry) { if (HistoryEntry->Target.Buffer) (void) RtlFreeHeap(Win32CsrApiHeap, 0, HistoryEntry->Target.Buffer); if (HistoryEntry->Device.Buffer) (void) RtlFreeHeap(Win32CsrApiHeap, 0, HistoryEntry->Device.Buffer); (void) RtlFreeHeap(Win32CsrApiHeap, 0, HistoryEntry); } } } /* EOF */