diff --git a/rosapps/applications/cmdutils/CMakeLists.txt b/rosapps/applications/cmdutils/CMakeLists.txt index 148f867258c..16c508ee6cf 100644 --- a/rosapps/applications/cmdutils/CMakeLists.txt +++ b/rosapps/applications/cmdutils/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(appwiz) add_subdirectory(cat) +add_subdirectory(hackssign) add_subdirectory(ntfsinfo) add_subdirectory(rosvboxmgmt) add_subdirectory(tee) diff --git a/rosapps/applications/cmdutils/hackssign/CMakeLists.txt b/rosapps/applications/cmdutils/hackssign/CMakeLists.txt new file mode 100644 index 00000000000..1eb93de3a63 --- /dev/null +++ b/rosapps/applications/cmdutils/hackssign/CMakeLists.txt @@ -0,0 +1,9 @@ +add_executable(hackssign_client client.c hackssign.rc) +set_module_type(hackssign_client win32cui UNICODE) +add_importlibs(hackssign_client msvcrt kernel32 advapi32) +add_cd_file(TARGET hackssign_client DESTINATION reactos/bin FOR all) + +add_library(hackssign_driver SHARED driver.c hackssign.rc) +set_module_type(hackssign_driver kernelmodedriver) +add_importlibs(hackssign_driver ntoskrnl hal) +add_cd_file(TARGET hackssign_driver DESTINATION reactos/bin FOR all) diff --git a/rosapps/applications/cmdutils/hackssign/client.c b/rosapps/applications/cmdutils/hackssign/client.c new file mode 100644 index 00000000000..d743f1f2678 --- /dev/null +++ b/rosapps/applications/cmdutils/hackssign/client.c @@ -0,0 +1,263 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: Hackssign application & driver + * FILE: cmdutils/hackssign/client.c + * PURPOSE: Client: Assign drive letter to shared folders for VMware/VBox VMs + * PROGRAMMERS: Pierre Schweitzer + */ + +#include +#include +#include + +#include "ioctl.h" + +/* DON'T MESS AROUND THIS! */ +typedef enum _HV_TYPES +{ + vmVMware, + vmVirtualBox, + vmMax, +} HV_TYPES; +PCWSTR hV[] = { L"vmware", L"virtualbox" }; +PCWSTR dev[] = { L"\\Device\\hgfs\\;", L"\\Device\\VBoxMiniRdr\\;" }; +PCWSTR unc[] = { L":\\vmware-host\\Shared Folders\\", L":\\vboxsvr\\" }; + +BOOL performDevIoCtl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize) +{ + BOOL ret; + HANDLE dev; + DWORD lpBytesReturned; + + dev = CreateFile(L"\\\\.\\hackssign", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (dev == INVALID_HANDLE_VALUE) + { + wprintf(L"Opening device failed\n"); + return FALSE; + } + + ret = DeviceIoControl(dev, dwIoControlCode, lpInBuffer, nInBufferSize, NULL, 0, &lpBytesReturned, NULL); + wprintf(L"Done: it %s with error: %lx\n", (ret != 0 ? L"succeed" : L"failed"), (ret != 0 ? ERROR_SUCCESS : GetLastError())); + + CloseHandle(dev); + + return ret; +} + + +BOOL startService() +{ + PWSTR fileName; + WCHAR path[MAX_PATH]; + SC_HANDLE hManager, hService; + + hManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); + if (hManager == NULL) + { + wprintf(L"Service manager opening failed\n"); + return FALSE; + } + + hService = OpenService(hManager, L"hackssign", SERVICE_START | SERVICE_STOP | DELETE); + if (hService == NULL) + { + if (GetModuleFileName(NULL, path, MAX_PATH) == 0) + { + wprintf(L"Getting own path failed\n"); + CloseServiceHandle(hManager); + return FALSE; + } + + fileName = wcsrchr(path, L'\\'); + if (fileName == NULL) + { + wprintf(L"Invalid path: %s\n", path); + CloseServiceHandle(hManager); + return FALSE; + } + + ++fileName; + *fileName = UNICODE_NULL; + wcscat(path, L"hackssign_driver.sys"); + + if (GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES) + { + wprintf(L"Driver not found: %s\n", path); + CloseServiceHandle(hManager); + return FALSE; + } + + hService = CreateService(hManager, L"hackssign", L"hackssign", + SERVICE_START | SERVICE_STOP | DELETE, SERVICE_KERNEL_DRIVER, + SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, path, NULL, NULL, + NULL, NULL, NULL); + if (hService == NULL) + { + wprintf(L"Creating service failed\n"); + CloseServiceHandle(hManager); + return FALSE; + } + } + + if (!StartService(hService, 0, NULL) && + GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) + { + wprintf(L"Starting service failed\n"); + CloseServiceHandle(hService); + CloseServiceHandle(hManager); + return FALSE; + } + + wprintf(L"Starting service succeed\n"); + CloseServiceHandle(hService); + CloseServiceHandle(hManager); + return TRUE; +} + +int assignLetter(WCHAR letter, PCWSTR path, PCWSTR device) +{ + BOOL ret; + DWORD len; + PWSTR str; + HV_TYPES vm; + WCHAR capsLetter; + DWORD inputBufferSize; + PASSIGN_INPUT inputBuffer; + + for (vm = vmVMware; vm < vmMax; ++vm) + { + if (_wcsicmp(device, hV[vm]) == 0) + { + break; + } + } + if (vm == vmMax) + { + wprintf(L"Unsupported VM type\n"); + return 1; + } + + if (iswalpha(letter) == 0) + { + wprintf(L"Invalid letter provided\n"); + return 1; + } + + capsLetter = towupper(letter); + if (capsLetter == L'C') + { + wprintf(L"Looks suspicious, won't proceed\n"); + return 1; + } + + len = wcslen(path); + if (len == 0) + { + wprintf(L"Invalid share name\n"); + return 1; + } + + if (wcschr(path, L'\\') != NULL) + { + wprintf(L"Only give the name of a share\n"); + return 1; + } + + inputBufferSize = len * sizeof(WCHAR) + sizeof(ASSIGN_INPUT) + (wcslen(dev[vm]) + wcslen(unc[vm]) + 2) * sizeof(WCHAR); + inputBuffer = malloc(inputBufferSize); + if (inputBuffer == NULL) + { + wprintf(L"Memory failure\n"); + return 1; + } + + inputBuffer->letter = capsLetter; + inputBuffer->offset = sizeof(ASSIGN_INPUT); + inputBuffer->len = len * sizeof(WCHAR) + (wcslen(dev[vm]) + wcslen(unc[vm]) + 1) * sizeof(WCHAR); + str = (PWSTR)((ULONG_PTR)inputBuffer + inputBuffer->offset); + swprintf(str, L"%s%c%s%s", dev[vm], capsLetter, unc[vm], path); + + if (!startService()) + { + free(inputBuffer); + return 1; + } + + Sleep(500); + + ret = performDevIoCtl(FSCTL_HACKSSIGN_ASSIGN, inputBuffer, inputBufferSize); + free(inputBuffer); + + return (ret == FALSE); +} + +int deleteLetter(WCHAR letter) +{ + WCHAR capsLetter; + + if (iswalpha(letter) == 0) + { + wprintf(L"Invalid letter provided\n"); + return 1; + } + + capsLetter = towupper(letter); + if (capsLetter == L'C') + { + wprintf(L"Looks suspicious, won't proceed\n"); + return 1; + } + + if (!startService()) + { + return 1; + } + + Sleep(500); + + return (performDevIoCtl(FSCTL_HACKSSIGN_DELETE, &capsLetter, sizeof(WCHAR)) == FALSE); +} + +void printUsage(void) +{ + wprintf(L"ReactOS Hackssign application\n"); + wprintf(L"\assign : Assign a drive letter to the share given the VM type\n"); + wprintf(L"\t\tVM types are: vmware or virtual\n"); + wprintf(L"\tdelete : delete driver letter assignation\n"); +} + +int wmain(int argc, wchar_t *argv[]) +{ + PCWSTR cmd; + + if (argc < 3) + { + printUsage(); + return 0; + } + + cmd = argv[1]; + + if (_wcsicmp(cmd, L"assign") == 0) + { + if (argc < 5) + { + printUsage(); + return 0; + } + + return assignLetter(argv[2][0], argv[3], argv[4]); + } + else if (_wcsicmp(cmd, L"delete") == 0) + { + return deleteLetter(argv[2][0]); + } + else + { + printUsage(); + return 0; + } +} diff --git a/rosapps/applications/cmdutils/hackssign/driver.c b/rosapps/applications/cmdutils/hackssign/driver.c new file mode 100644 index 00000000000..47785a71d06 --- /dev/null +++ b/rosapps/applications/cmdutils/hackssign/driver.c @@ -0,0 +1,198 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: Hackssign application & driver + * FILE: cmdutils/hackssign/driver.c + * PURPOSE: Driver: Assign drive letter to shared folders for VMware/VBox VMs + * PROGRAMMERS: Pierre Schweitzer + */ + +#include +#include +#include +#define NDEBUG +#include + +#include "ioctl.h" + +typedef struct _HS_VCB +{ + SHARE_ACCESS shareAccess; +} HS_VCB, *PHS_VCB; + +ERESOURCE globalLock; +PDEVICE_OBJECT gDevObj; + +NTSTATUS +NTAPI +hsDispatch(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PHS_VCB vcb; + NTSTATUS status; + WCHAR dosBuffer[7]; + PFILE_OBJECT fileObject; + PIO_STACK_LOCATION stack; + PASSIGN_INPUT inputBuffer; + UNICODE_STRING target, source; + + FsRtlEnterFileSystem(); + ExAcquireResourceExclusiveLite(&globalLock, TRUE); + + stack = IoGetCurrentIrpStackLocation(Irp); + fileObject = stack->FileObject; + switch (stack->MajorFunction) + { + case IRP_MJ_CREATE: + if (fileObject->FileName.Length != 0) + { + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + status = IoCheckShareAccess(stack->Parameters.Create.SecurityContext->DesiredAccess, + stack->Parameters.Create.ShareAccess, + fileObject, &((PHS_VCB)DeviceObject->DeviceExtension)->shareAccess, TRUE); + if (NT_SUCCESS(status)) + { + DPRINT1("Device opened\n"); + + Irp->IoStatus.Information = FILE_OPENED; + fileObject->FsContext = DeviceObject->DeviceExtension; + status = STATUS_SUCCESS; + } + break; + + case IRP_MJ_FILE_SYSTEM_CONTROL: + if (stack->Parameters.FileSystemControl.FsControlCode == FSCTL_HACKSSIGN_ASSIGN) + { + if (stack->Parameters.FileSystemControl.InputBufferLength <= sizeof(ASSIGN_INPUT) || + Irp->AssociatedIrp.SystemBuffer == NULL) + { + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + inputBuffer = Irp->AssociatedIrp.SystemBuffer; + + swprintf(dosBuffer, L"\\??\\%c:", inputBuffer->letter); + RtlInitUnicodeString(&source, dosBuffer); + target.Buffer = (PWSTR)((ULONG_PTR)inputBuffer + inputBuffer->offset); + target.Length = inputBuffer->len; + target.MaximumLength = target.Length; + + DPRINT1("Will link %wZ to %wZ\n", &source, &target); + + status = IoCreateSymbolicLink(&source, &target); + break; + } + else if (stack->Parameters.FileSystemControl.FsControlCode == FSCTL_HACKSSIGN_DELETE) + { + if (stack->Parameters.FileSystemControl.InputBufferLength < sizeof(WCHAR) || + Irp->AssociatedIrp.SystemBuffer == NULL) + { + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + inputBuffer = Irp->AssociatedIrp.SystemBuffer; + + swprintf(dosBuffer, L"\\??\\%c:", inputBuffer->letter); + RtlInitUnicodeString(&source, dosBuffer); + + DPRINT1("Will unlink %wZ\n", &source); + + status = IoDeleteSymbolicLink(&source); + break; + } + + status = STATUS_INVALID_DEVICE_REQUEST; + break; + + case IRP_MJ_CLEANUP: + vcb = fileObject->FsContext; + if (vcb == NULL) + { + status = STATUS_INVALID_HANDLE; + break; + } + + DPRINT1("Device cleaned up\n"); + IoRemoveShareAccess(fileObject, &vcb->shareAccess); + status = STATUS_SUCCESS; + break; + + case IRP_MJ_CLOSE: + vcb = fileObject->FsContext; + if (vcb == NULL) + { + status = STATUS_INVALID_HANDLE; + break; + } + + DPRINT1("Device closed\n"); + fileObject->FsContext = NULL; + status = STATUS_SUCCESS; + break; + + default: + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + ExReleaseResourceLite(&globalLock); + FsRtlExitFileSystem(); + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +VOID +NTAPI +hsUnload(PDRIVER_OBJECT DriverObject) +{ + IoDeleteDevice(gDevObj); + ExDeleteResourceLite(&globalLock); +} + +NTSTATUS +NTAPI +DriverEntry(PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +{ + NTSTATUS status; + PDEVICE_OBJECT devObj; + UNICODE_STRING devName, uDevName; + + DPRINT1("Starting hackssign driver\n"); + + RtlInitUnicodeString(&devName, L"\\Device\\hackssign"); + status = IoCreateDevice(DriverObject, sizeof(HS_VCB), &devName, FILE_DEVICE_FILE_SYSTEM, 0, FALSE, &devObj); + if (!NT_SUCCESS(status)) + { + DPRINT1("IoCreateDevice failed\n"); + return status; + } + + RtlInitUnicodeString(&uDevName, L"\\??\\hackssign"); + status = IoCreateSymbolicLink(&uDevName, &devName); + if (!NT_SUCCESS(status)) + { + DPRINT1("IoCreateSymbolicLink failed\n"); + IoDeleteDevice(devObj); + return status; + } + + gDevObj = devObj; + ExInitializeResourceLite(&globalLock); + RtlZeroMemory(devObj->DeviceExtension, sizeof(HS_VCB)); + + DriverObject->DriverUnload = hsUnload; + DriverObject->MajorFunction[IRP_MJ_CREATE] = hsDispatch; + DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = hsDispatch; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = hsDispatch; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = hsDispatch; + + return STATUS_SUCCESS; +} diff --git a/rosapps/applications/cmdutils/hackssign/hackssign.rc b/rosapps/applications/cmdutils/hackssign/hackssign.rc new file mode 100644 index 00000000000..1b791f98978 --- /dev/null +++ b/rosapps/applications/cmdutils/hackssign/hackssign.rc @@ -0,0 +1,5 @@ + +#define REACTOS_STR_FILE_DESCRIPTION "Hack assign letters\0" +#define REACTOS_STR_INTERNAL_NAME "hackssign\0" +#define REACTOS_STR_ORIGINAL_FILENAME "hackssign.exe\0" +#include diff --git a/rosapps/applications/cmdutils/hackssign/ioctl.h b/rosapps/applications/cmdutils/hackssign/ioctl.h new file mode 100644 index 00000000000..3d293997e86 --- /dev/null +++ b/rosapps/applications/cmdutils/hackssign/ioctl.h @@ -0,0 +1,9 @@ +typedef struct _ASSIGN_INPUT +{ + WCHAR letter; + USHORT offset; + USHORT len; +} ASSIGN_INPUT, *PASSIGN_INPUT; + +#define FSCTL_HACKSSIGN_ASSIGN CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x42, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_HACKSSIGN_DELETE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) diff --git a/rosapps/applications/cmdutils/rosvboxmgmt/rosvboxmgmt.c b/rosapps/applications/cmdutils/rosvboxmgmt/rosvboxmgmt.c index 20704d6159e..ef3982a08e2 100644 --- a/rosapps/applications/cmdutils/rosvboxmgmt/rosvboxmgmt.c +++ b/rosapps/applications/cmdutils/rosvboxmgmt/rosvboxmgmt.c @@ -1,3 +1,11 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS VBox Shared Folders Management + * FILE: cmdutils/hackssign/client.c + * PURPOSE: Communicate with VBox mini redirector to deal with shared folders + * PROGRAMMERS: Pierre Schweitzer + */ + #include #include #include