From a63e424516e4f7dfdd994bada9f9b5b31686e39a Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Mon, 18 Apr 2011 21:48:19 +0000 Subject: [PATCH] Sam Arun Raj Seeniraj: [KERNEL32] - DefineDosDeviceW() is implemented and calls into csrss.exe CsrDefineDosDevice(). - Fixed a minor bug in DefineDosDeviceA(), as calling RtlCreateUnicodeStringFromAsciiz() prevented NULL lpTargetPath to be passed down to DefineDosDeviceW(). - Fixed a minor bug in QueryDosDeviceW() that causes lpTargetPath buffer to be returned with NULL string terminator placed at the wrong point in the buffer. [WIN32CSR.DLL] - Implemented CsrDefineDosDevice() in win32csr.dll, the symbolic links are created in global name space currently. [SUBST.EXE] - Implemented a subst.exe clone. See issue #993 for more details. svn path=/trunk/; revision=51393 --- reactos/base/system/subst/subst.c | 257 +++++++++ reactos/base/system/subst/subst.rbuild | 9 + reactos/base/system/subst/subst.rc | 5 + reactos/base/system/system.rbuild | 3 + reactos/boot/bootdata/packages/reactos.dff | 1 + reactos/dll/win32/kernel32/file/dosdev.c | 222 ++++++-- reactos/include/reactos/subsys/csrss/csrss.h | 9 + .../subsystems/win32/csrss/win32csr/dllmain.c | 10 + .../subsystems/win32/csrss/win32csr/file.c | 509 +++++++++++++++++- .../subsystems/win32/csrss/win32csr/file.h | 11 + 10 files changed, 1003 insertions(+), 33 deletions(-) create mode 100644 reactos/base/system/subst/subst.c create mode 100644 reactos/base/system/subst/subst.rbuild create mode 100644 reactos/base/system/subst/subst.rc diff --git a/reactos/base/system/subst/subst.c b/reactos/base/system/subst/subst.c new file mode 100644 index 00000000000..7cb92563eb8 --- /dev/null +++ b/reactos/base/system/subst/subst.c @@ -0,0 +1,257 @@ +/* PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/system/subst/subst.c + * PURPOSE: Associates a path with a drive letter + * PROGRAMMERS: Sam Arun Raj + */ + +/* INCLUDES *****************************************************************/ + +#define LEAN_AND_MEAN +#include +#include +#include +#include +#define NDEBUG +#include + +/* FUNCTIONS ****************************************************************/ + +void PrintError(DWORD ErrCode) +{ + TCHAR *buffer = (TCHAR*) calloc(2048, + sizeof(TCHAR)); + TCHAR *msg = NULL; + + if (buffer) + { + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + ErrCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (TCHAR*)&msg, + 0, + NULL); + _sntprintf(buffer, + 2048, + _T("Failed with error code 0x%x: %s\n"), + ErrCode, + msg); + _tprintf(_T("%s"), + buffer); + if (msg) + LocalFree(msg); + free(buffer); + } +} + +void DisplaySubstUsage() +{ + _tprintf(_T("Associates a path with a drive letter.\n\n")); + _tprintf(_T("SUBST [drive1: [drive2:]path]\n")); + _tprintf(_T("SUBST drive1: /D\n\n")); + _tprintf(_T(" drive1: Specifies a virtual drive to which you want to assign a path.\n")); + _tprintf(_T(" [drive2:]path Specifies a physical drive and path you want to assign to\n")); + _tprintf(_T(" a virtual drive.\n")); + _tprintf(_T(" /D Deletes a substituted (virtual) drive.\n\n")); + _tprintf(_T("Type SUBST with no parameters to display a list of current virtual drives.\n")); +} + +BOOLEAN IsSubstedDrive(TCHAR *Drive) +{ + BOOLEAN Result = FALSE; + LPTSTR lpTargetPath = NULL; + DWORD CharCount, dwSize; + + if (_tcslen(Drive) > 2) + return FALSE; + + dwSize = sizeof(TCHAR) * MAX_PATH; + lpTargetPath = (LPTSTR) malloc(sizeof(TCHAR) * MAX_PATH); + if ( lpTargetPath) + { + CharCount = QueryDosDevice(Drive, + lpTargetPath, + dwSize / sizeof(TCHAR)); + while (! CharCount && + GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + free(lpTargetPath); + dwSize *= 2; + lpTargetPath = (LPTSTR) malloc(dwSize); + if (lpTargetPath) + { + CharCount = QueryDosDevice(Drive, + lpTargetPath, + dwSize / sizeof(TCHAR)); + } + } + + if (CharCount) + { + if ( _tcsncmp(lpTargetPath, _T("\\??\\"), 4) == 0 && + ( (lpTargetPath[4] >= _T('A') && + lpTargetPath[4] <= _T('Z')) || + (lpTargetPath[4] >= _T('a') && + lpTargetPath[4] <= _T('z')) ) ) + { + Result = TRUE; + } + } + free(lpTargetPath); + } + return Result; +} + +void DumpSubstedDrives() +{ + TCHAR Drive[3] = _T("A:"); + LPTSTR lpTargetPath = NULL; + DWORD CharCount, dwSize; + INT i = 0; + + dwSize = sizeof(TCHAR) * MAX_PATH; + lpTargetPath = (LPTSTR) malloc(sizeof(TCHAR) * MAX_PATH); + if (! lpTargetPath) + return; + + while (i < 26) + { + Drive[0] = _T('A') + i; + CharCount = QueryDosDevice(Drive, + lpTargetPath, + dwSize / sizeof(TCHAR)); + while (! CharCount && + GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + free(lpTargetPath); + dwSize *= 2; + lpTargetPath = (LPTSTR) malloc(dwSize); + if (lpTargetPath) + { + CharCount = QueryDosDevice(Drive, + lpTargetPath, + dwSize / sizeof(TCHAR)); + } + } + + if (! CharCount) + { + i++; + continue; + } + else + { + if ( _tcsncmp(lpTargetPath, _T("\\??\\"), 4) == 0 && + ( (lpTargetPath[4] >= _T('A') && + lpTargetPath[4] <= _T('Z')) || + (lpTargetPath[4] >= _T('a') && + lpTargetPath[4] <= _T('z')) ) ) + { + _tprintf(_T("%s\\: => %s\n"), + Drive, + lpTargetPath + 4); + } + } + i++; + } + free(lpTargetPath); +} + +int DeleteSubst(TCHAR* Drive) +{ + BOOL Result; + + if (_tcslen(Drive) > 2) + { + _tprintf(_T("Invalid parameter - %s\n"), + Drive); + return 1; + } + + if (! IsSubstedDrive(Drive)) + { + _tprintf(_T("Invalid Parameter - %s\n"), + Drive); + return 1; + } + + Result = DefineDosDevice(DDD_REMOVE_DEFINITION, + Drive, + NULL); + if (! Result) + { + PrintError(GetLastError()); + return 1; + } + return 0; +} + +int AddSubst(TCHAR* Drive, TCHAR *Path) +{ + BOOL Result; + + if (_tcslen(Drive) > 2) + { + _tprintf(_T("Invalid parameter - %s\n"), + Drive); + return 1; + } + + if (IsSubstedDrive(Drive)) + { + _tprintf(_T("Drive already SUBSTed\n")); + return 1; + } + + Result = DefineDosDevice(0, + Drive, + Path); + if (! Result) + { + PrintError(GetLastError()); + return 1; + } + return 0; +} + +int _tmain(int argc, TCHAR* argv[]) +{ + INT i; + + for (i = 0; i < argc; i++) + { + if (!_tcsicmp(argv[i], _T("/?"))) + { + DisplaySubstUsage(); + return 0; + } + } + + if (argc < 3) + { + if (argc >= 2) + { + _tprintf(_T("Invalid parameter - %s\n"), + argv[1]); + return 1; + } + DumpSubstedDrives(); + return 0; + } + + if (argc > 3) + { + _tprintf(_T("Incorrect number of parameters - %s\n"), + argv[3]); + return 1; + } + + if (! _tcsicmp(argv[1], _T("/D"))) + return DeleteSubst(argv[2]); + if (! _tcsicmp(argv[2], _T("/D"))) + return DeleteSubst(argv[1]); + return AddSubst(argv[1], argv[2]); +} + +/* EOF */ diff --git a/reactos/base/system/subst/subst.rbuild b/reactos/base/system/subst/subst.rbuild new file mode 100644 index 00000000000..fe93acb95e1 --- /dev/null +++ b/reactos/base/system/subst/subst.rbuild @@ -0,0 +1,9 @@ + + + + include/reactos/wine + . + kernel32 + subst.c + subst.rc + diff --git a/reactos/base/system/subst/subst.rc b/reactos/base/system/subst/subst.rc new file mode 100644 index 00000000000..b81ea2c6a7b --- /dev/null +++ b/reactos/base/system/subst/subst.rc @@ -0,0 +1,5 @@ +#include +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Virtual Drive Utility Version 1.0 \0" +#define REACTOS_STR_INTERNAL_NAME "subst\0" +#define REACTOS_STR_ORIGINAL_FILENAME "subst.exe\0" +#include diff --git a/reactos/base/system/system.rbuild b/reactos/base/system/system.rbuild index 8dd6d2aa0a4..7e7d348a6b0 100644 --- a/reactos/base/system/system.rbuild +++ b/reactos/base/system/system.rbuild @@ -10,6 +10,9 @@ + + + diff --git a/reactos/boot/bootdata/packages/reactos.dff b/reactos/boot/bootdata/packages/reactos.dff index 778dac88b98..85f7955fdc8 100644 --- a/reactos/boot/bootdata/packages/reactos.dff +++ b/reactos/boot/bootdata/packages/reactos.dff @@ -115,6 +115,7 @@ base\shell\explorer-new\explorer_new.exe 4 optional base\system\autochk\autochk.exe 1 base\system\bootok\bootok.exe 1 base\system\expand\expand.exe 1 +base\system\subst\subst.exe 1 base\system\format\format.exe 1 base\system\lsass\lsass.exe 1 base\system\msiexec\msiexec.exe 1 diff --git a/reactos/dll/win32/kernel32/file/dosdev.c b/reactos/dll/win32/kernel32/file/dosdev.c index 1e15166bb64..0d65a74140c 100644 --- a/reactos/dll/win32/kernel32/file/dosdev.c +++ b/reactos/dll/win32/kernel32/file/dosdev.c @@ -14,6 +14,7 @@ #include #define NDEBUG #include +#include DEBUG_CHANNEL(kernel32file); /* FUNCTIONS *****************************************************************/ @@ -29,44 +30,55 @@ DefineDosDeviceA( LPCSTR lpTargetPath ) { - UNICODE_STRING DeviceNameU; - UNICODE_STRING TargetPathU; - BOOL Result; + UNICODE_STRING DeviceNameU = {0}; + UNICODE_STRING TargetPathU = {0}; + BOOL Result; - if (!RtlCreateUnicodeStringFromAsciiz (&DeviceNameU, - (LPSTR)lpDeviceName)) - { - SetLastError (ERROR_NOT_ENOUGH_MEMORY); - return 0; - } + if (lpDeviceName && + ! RtlCreateUnicodeStringFromAsciiz(&DeviceNameU, + (LPSTR)lpDeviceName)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } - if (!RtlCreateUnicodeStringFromAsciiz (&TargetPathU, - (LPSTR)lpTargetPath)) - { - RtlFreeHeap (RtlGetProcessHeap (), - 0, - DeviceNameU.Buffer); - SetLastError (ERROR_NOT_ENOUGH_MEMORY); - return 0; - } + if (lpTargetPath && + ! RtlCreateUnicodeStringFromAsciiz(&TargetPathU, + (LPSTR)lpTargetPath)) + { + if (DeviceNameU.Buffer) + { + RtlFreeHeap(RtlGetProcessHeap (), + 0, + DeviceNameU.Buffer); + } + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } - Result = DefineDosDeviceW (dwFlags, - DeviceNameU.Buffer, - TargetPathU.Buffer); + Result = DefineDosDeviceW(dwFlags, + DeviceNameU.Buffer, + TargetPathU.Buffer); - RtlFreeHeap (RtlGetProcessHeap (), - 0, - TargetPathU.Buffer); - RtlFreeHeap (RtlGetProcessHeap (), - 0, - DeviceNameU.Buffer); + if (TargetPathU.Buffer) + { + RtlFreeHeap(RtlGetProcessHeap (), + 0, + TargetPathU.Buffer); + } - return Result; + if (DeviceNameU.Buffer) + { + RtlFreeHeap(RtlGetProcessHeap (), + 0, + DeviceNameU.Buffer); + } + return Result; } /* - * @unimplemented + * @implemented */ BOOL WINAPI @@ -76,8 +88,154 @@ DefineDosDeviceW( LPCWSTR lpTargetPath ) { - UNIMPLEMENTED; - return FALSE; + ULONG ArgumentCount; + ULONG BufferSize; + PCSR_CAPTURE_BUFFER CaptureBuffer; + CSR_API_MESSAGE Request; + NTSTATUS Status; + UNICODE_STRING NtTargetPathU; + UNICODE_STRING DeviceNameU; + UNICODE_STRING DeviceUpcaseNameU; + HANDLE hUser32; + DEV_BROADCAST_VOLUME dbcv; + BOOL Result = TRUE; + DWORD dwRecipients; + typedef long (WINAPI *BSM_type)(DWORD,LPDWORD,UINT,WPARAM,LPARAM); + BSM_type BSM_ptr; + + if ( (dwFlags & 0xFFFFFFF0) || + ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) && + ! (dwFlags & DDD_REMOVE_DEFINITION)) ) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + ArgumentCount = 1; + BufferSize = 0; + if (! lpTargetPath) + { + RtlInitUnicodeString(&NtTargetPathU, + NULL); + } + else + { + if (dwFlags & DDD_RAW_TARGET_PATH) + { + RtlInitUnicodeString(&NtTargetPathU, + lpTargetPath); + } + else + { + if (! RtlDosPathNameToNtPathName_U(lpTargetPath, + &NtTargetPathU, + 0, + 0)) + { + WARN("RtlDosPathNameToNtPathName_U() failed\n"); + BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID); + return FALSE; + } + } + ArgumentCount = 2; + BufferSize += NtTargetPathU.Length; + } + + RtlInitUnicodeString(&DeviceNameU, + lpDeviceName); + RtlUpcaseUnicodeString(&DeviceUpcaseNameU, + &DeviceNameU, + TRUE); + BufferSize += DeviceUpcaseNameU.Length; + + CaptureBuffer = CsrAllocateCaptureBuffer(ArgumentCount, + BufferSize); + if (! CaptureBuffer) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + Result = FALSE; + } + else + { + Request.Data.DefineDosDeviceRequest.dwFlags = dwFlags; + + CsrCaptureMessageBuffer(CaptureBuffer, + (PVOID)DeviceUpcaseNameU.Buffer, + DeviceUpcaseNameU.Length, + (PVOID*)&Request.Data.DefineDosDeviceRequest.DeviceName.Buffer); + + Request.Data.DefineDosDeviceRequest.DeviceName.Length = + DeviceUpcaseNameU.Length; + Request.Data.DefineDosDeviceRequest.DeviceName.MaximumLength = + DeviceUpcaseNameU.Length; + + if (NtTargetPathU.Buffer) + { + CsrCaptureMessageBuffer(CaptureBuffer, + (PVOID)NtTargetPathU.Buffer, + NtTargetPathU.Length, + (PVOID*)&Request.Data.DefineDosDeviceRequest.TargetName.Buffer); + } + Request.Data.DefineDosDeviceRequest.TargetName.Length = + NtTargetPathU.Length; + Request.Data.DefineDosDeviceRequest.TargetName.MaximumLength = + NtTargetPathU.Length; + + Status = CsrClientCallServer(&Request, + CaptureBuffer, + MAKE_CSR_API(DEFINE_DOS_DEVICE, CSR_CONSOLE), + sizeof(CSR_API_MESSAGE)); + CsrFreeCaptureBuffer(CaptureBuffer); + + if (! NT_SUCCESS(Status) || + ! NT_SUCCESS(Status = Request.Status)) + { + WARN("CsrClientCallServer() failed (Status %lx)\n", + Status); + SetLastErrorByStatus(Status); + Result = FALSE; + } + else + { + if (! (dwFlags & DDD_NO_BROADCAST_SYSTEM) && + DeviceUpcaseNameU.Length == 2 * sizeof(WCHAR) && + DeviceUpcaseNameU.Buffer[1] == L':' && + ( (DeviceUpcaseNameU.Buffer[0] - L'A') < 26 )) + { + hUser32 = LoadLibraryA("user32.dll"); + if (hUser32) + { + BSM_ptr = (BSM_type) + GetProcAddress(hUser32, "BroadcastSystemMessageW"); + if (BSM_ptr) + { + dwRecipients = BSM_APPLICATIONS; + dbcv.dbcv_size = sizeof(DEV_BROADCAST_VOLUME); + dbcv.dbcv_devicetype = DBT_DEVTYP_VOLUME; + dbcv.dbcv_reserved = 0; + dbcv.dbcv_unitmask |= + (1 << (DeviceUpcaseNameU.Buffer[0] - L'A')); + dbcv.dbcv_flags = DBTF_NET; + (void) BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK, + &dwRecipients, + WM_DEVICECHANGE, + (WPARAM)DBT_DEVICEARRIVAL, + (LPARAM)&dbcv); + } + FreeLibrary(hUser32); + } + } + } + } + + if (NtTargetPathU.Buffer) + { + RtlFreeHeap(RtlGetProcessHeap(), + 0, + NtTargetPathU.Buffer); + } + RtlFreeUnicodeString(&DeviceUpcaseNameU); + return Result; } @@ -250,7 +408,7 @@ QueryDosDeviceW( TRACE ("TargetLength: %hu\n", UnicodeString.Length); TRACE ("Target: '%wZ'\n", &UnicodeString); - Length = ReturnLength / sizeof(WCHAR); + Length = UnicodeString.Length / sizeof(WCHAR); if (Length < ucchMax) { /* Append null-charcter */ diff --git a/reactos/include/reactos/subsys/csrss/csrss.h b/reactos/include/reactos/subsys/csrss/csrss.h index 47c5addc8b8..4c9f44fd43c 100644 --- a/reactos/include/reactos/subsys/csrss/csrss.h +++ b/reactos/include/reactos/subsys/csrss/csrss.h @@ -518,6 +518,13 @@ typedef struct UINT UniqueID; } CSRSS_GET_TEMP_FILE, *PCSRSS_GET_TEMP_FILE; +typedef struct +{ + UNICODE_STRING DeviceName; + UNICODE_STRING TargetName; + DWORD dwFlags; +} CSRSS_DEFINE_DOS_DEVICE, *PCSRSS_DEFINE_DOS_DEVICE; + #define CSR_API_MESSAGE_HEADER_SIZE(Type) (FIELD_OFFSET(CSR_API_MESSAGE, Data) + sizeof(Type)) #define CSRSS_MAX_WRITE_CONSOLE (LPC_MAX_DATA_LENGTH - CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE)) #define CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR (LPC_MAX_DATA_LENGTH - CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_CHAR)) @@ -598,6 +605,7 @@ typedef struct #define GET_HISTORY_INFO (0x46) #define SET_HISTORY_INFO (0x47) #define GET_TEMP_FILE (0x48) +#define DEFINE_DOS_DEVICE (0X49) /* Keep in sync with definition below. */ #define CSRSS_HEADER_SIZE (sizeof(PORT_MESSAGE) + sizeof(ULONG) + sizeof(NTSTATUS)) @@ -680,6 +688,7 @@ typedef struct _CSR_API_MESSAGE CSRSS_GET_HISTORY_INFO GetHistoryInfo; CSRSS_SET_HISTORY_INFO SetHistoryInfo; CSRSS_GET_TEMP_FILE GetTempFile; + CSRSS_DEFINE_DOS_DEVICE DefineDosDeviceRequest; } Data; } CSR_API_MESSAGE, *PCSR_API_MESSAGE; diff --git a/reactos/subsystems/win32/csrss/win32csr/dllmain.c b/reactos/subsystems/win32/csrss/win32csr/dllmain.c index 06112ab1f42..013b8b8556d 100644 --- a/reactos/subsystems/win32/csrss/win32csr/dllmain.c +++ b/reactos/subsystems/win32/csrss/win32csr/dllmain.c @@ -9,11 +9,14 @@ /* INCLUDES ******************************************************************/ #define NDEBUG #include "w32csr.h" +#include "file.h" #include /* Not defined in any header file */ extern VOID WINAPI PrivateCsrssManualGuiCheck(LONG Check); extern VOID WINAPI InitializeAppSwitchHook(); +extern LIST_ENTRY DosDeviceHistory; +extern RTL_CRITICAL_SECTION Win32CsrDefineDosDeviceCritSec; /* GLOBALS *******************************************************************/ @@ -88,6 +91,7 @@ static CSRSS_API_DEFINITION Win32CsrApiDefinitions[] = CSRSS_DEFINE_API(GET_HISTORY_INFO, CsrGetHistoryInfo), CSRSS_DEFINE_API(SET_HISTORY_INFO, CsrSetHistoryInfo), CSRSS_DEFINE_API(GET_TEMP_FILE, CsrGetTempFile), + CSRSS_DEFINE_API(DEFINE_DOS_DEVICE, CsrDefineDosDevice), { 0, 0, NULL } }; @@ -104,6 +108,10 @@ DllMain(HANDLE hDll, InitializeAppSwitchHook(); } + if (DLL_PROCESS_DETACH == dwReason) + { + CsrCleanupDefineDosDevice(); + } return TRUE; } @@ -174,6 +182,8 @@ Win32CsrInitialization(PCSRSS_API_DEFINITION *ApiDefinitions, ServerProcs->ProcessInheritProc = Win32CsrDuplicateHandleTable; ServerProcs->ProcessDeletedProc = Win32CsrReleaseConsole; + Status = RtlInitializeCriticalSection(&Win32CsrDefineDosDeviceCritSec); + InitializeListHead(&DosDeviceHistory); return TRUE; } diff --git a/reactos/subsystems/win32/csrss/win32csr/file.c b/reactos/subsystems/win32/csrss/win32csr/file.c index d7e8414b0dd..8a6ba73b3c7 100644 --- a/reactos/subsystems/win32/csrss/win32csr/file.c +++ b/reactos/subsystems/win32/csrss/win32csr/file.c @@ -10,13 +10,15 @@ /* INCLUDES ******************************************************************/ #include - #define NDEBUG #include +#include "file.h" /* GLOBALS *******************************************************************/ UINT CsrGetTempFileUnique; +LIST_ENTRY DosDeviceHistory; +RTL_CRITICAL_SECTION Win32CsrDefineDosDeviceCritSec; /* FUNCTIONS *****************************************************************/ @@ -31,3 +33,508 @@ CSR_API(CsrGetTempFile) 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)", + 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)", + &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)", + &DeviceName, Status); + _SEH2_LEAVE; + } + + Status = NtClose(LinkHandle); + LinkHandle = NULL; + if (! NT_SUCCESS(Status)) + { + DPRINT1("NtClose(%wZ) failed (Status %lx)", + &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)", + Status); + _SEH2_LEAVE; + } + + Status = RtlCreateAcl(Dacl, + Length, + ACL_REVISION); + if (! NT_SUCCESS(Status)) + { + DPRINT1("RtlCreateAcl() failed (Status %lx)", + 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)", + 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)", + &DeviceName, Status); + } + } + else + { + DPRINT1("NtCreateSymbolicLinkObject(%wZ) failed (Status %lx)", + &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() +{ + 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 */ diff --git a/reactos/subsystems/win32/csrss/win32csr/file.h b/reactos/subsystems/win32/csrss/win32csr/file.h index c163ee53254..fa33b62efd2 100644 --- a/reactos/subsystems/win32/csrss/win32csr/file.h +++ b/reactos/subsystems/win32/csrss/win32csr/file.h @@ -11,7 +11,18 @@ #include "api.h" +typedef struct tagCSRSS_DOS_DEVICE_HISTORY_ENTRY +{ + UNICODE_STRING Device; + UNICODE_STRING Target; + LIST_ENTRY Entry; +} CSRSS_DOS_DEVICE_HISTORY_ENTRY, *PCSRSS_DOS_DEVICE_HISTORY_ENTRY; + /* Api functions */ CSR_API(CsrGetTempFile); +CSR_API(CsrDefineDosDevice); + +/* functions */ +void CsrCleanupDefineDosDevice(); /* EOF */