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
This commit is contained in:
Aleksey Bragin 2011-04-18 21:48:19 +00:00
parent 46662954bd
commit a63e424516
10 changed files with 1003 additions and 33 deletions

View file

@ -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 <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <tchar.h>
#define NDEBUG
#include <debug.h>
/* 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 */

View file

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
<module name="subst" type="win32cui" installbase="system32" installname="subst.exe" >
<include base="ReactOS">include/reactos/wine</include>
<include base="subst">.</include>
<library>kernel32</library>
<file>subst.c</file>
<file>subst.rc</file>
</module>

View file

@ -0,0 +1,5 @@
#include <windows.h>
#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 <reactos/version.rc>

View file

@ -10,6 +10,9 @@
<directory name="expand">
<xi:include href="expand/expand.rbuild" />
</directory>
<directory name="subst">
<xi:include href="subst/subst.rbuild" />
</directory>
<directory name="format">
<xi:include href="format/format.rbuild" />
</directory>

View file

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

View file

@ -14,6 +14,7 @@
#include <k32.h>
#define NDEBUG
#include <debug.h>
#include <Dbt.h>
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 */

View file

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

View file

@ -9,11 +9,14 @@
/* INCLUDES ******************************************************************/
#define NDEBUG
#include "w32csr.h"
#include "file.h"
#include <debug.h>
/* 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;
}

View file

@ -10,13 +10,15 @@
/* INCLUDES ******************************************************************/
#include <w32csr.h>
#define NDEBUG
#include <debug.h>
#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 */

View file

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