mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-23 17:03:12 -05:00
launcher: access control
This commit is contained in:
parent
ceef2bf55e
commit
6971f4d6ae
@ -26,6 +26,7 @@ typedef struct
|
|||||||
PWSTR ClassName;
|
PWSTR ClassName;
|
||||||
PWSTR InstanceName;
|
PWSTR InstanceName;
|
||||||
PWSTR CommandLine;
|
PWSTR CommandLine;
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
||||||
DWORD ProcessId;
|
DWORD ProcessId;
|
||||||
HANDLE Process;
|
HANDLE Process;
|
||||||
HANDLE ProcessWait;
|
HANDLE ProcessWait;
|
||||||
@ -126,16 +127,18 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess, PWSTR Security)
|
static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor)
|
||||||
{
|
{
|
||||||
static GENERIC_MAPPING GenericMapping =
|
static GENERIC_MAPPING GenericMapping =
|
||||||
{
|
{
|
||||||
.GenericRead = FILE_GENERIC_READ,
|
.GenericRead = STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS |
|
||||||
.GenericWrite = FILE_GENERIC_WRITE,
|
SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS,
|
||||||
.GenericExecute = FILE_GENERIC_EXECUTE,
|
.GenericWrite = STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG,
|
||||||
.GenericAll = FILE_ALL_ACCESS,
|
.GenericExecute = STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP |
|
||||||
|
SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL,
|
||||||
|
.GenericAll = SERVICE_ALL_ACCESS,
|
||||||
};
|
};
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
|
||||||
UINT8 PrivilegeSetBuf[sizeof(PRIVILEGE_SET) + 15 * sizeof(LUID_AND_ATTRIBUTES)];
|
UINT8 PrivilegeSetBuf[sizeof(PRIVILEGE_SET) + 15 * sizeof(LUID_AND_ATTRIBUTES)];
|
||||||
PPRIVILEGE_SET PrivilegeSet = (PVOID)PrivilegeSetBuf;
|
PPRIVILEGE_SET PrivilegeSet = (PVOID)PrivilegeSetBuf;
|
||||||
DWORD PrivilegeSetLength = sizeof PrivilegeSetBuf;
|
DWORD PrivilegeSetLength = sizeof PrivilegeSetBuf;
|
||||||
@ -143,22 +146,12 @@ static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
|
|||||||
BOOL AccessStatus;
|
BOOL AccessStatus;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(Security, SDDL_REVISION_1,
|
|
||||||
&SecurityDescriptor, 0))
|
|
||||||
{
|
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AccessCheck(SecurityDescriptor, ClientToken, DesiredAccess,
|
if (AccessCheck(SecurityDescriptor, ClientToken, DesiredAccess,
|
||||||
&GenericMapping, PrivilegeSet, &PrivilegeSetLength, &GrantedAccess, &AccessStatus))
|
&GenericMapping, PrivilegeSet, &PrivilegeSetLength, &GrantedAccess, &AccessStatus))
|
||||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||||
else
|
else
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
|
||||||
exit:
|
|
||||||
LocalFree(SecurityDescriptor);
|
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,6 +164,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
DWORD RegResult, RegSize, SecurityLen;
|
DWORD RegResult, RegSize, SecurityLen;
|
||||||
DWORD ClassNameSize, InstanceNameSize;
|
DWORD ClassNameSize, InstanceNameSize;
|
||||||
WCHAR Executable[MAX_PATH], CommandLine[512], Security[512] = L"O:SYG:SY";
|
WCHAR Executable[MAX_PATH], CommandLine[512], Security[512] = L"O:SYG:SY";
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
||||||
STARTUPINFOW StartupInfo;
|
STARTUPINFOW StartupInfo;
|
||||||
PROCESS_INFORMATION ProcessInfo;
|
PROCESS_INFORMATION ProcessInfo;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
@ -225,13 +219,20 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
RegCloseKey(RegKey);
|
RegCloseKey(RegKey);
|
||||||
RegKey = 0;
|
RegKey = 0;
|
||||||
|
|
||||||
if (L'\0' != Security)
|
if (L'\0' == Security)
|
||||||
|
lstrcpyW(Security, L"" SVC_INSTANCE_DEFAULT_SDDL);
|
||||||
|
|
||||||
|
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(Security, SDDL_REVISION_1,
|
||||||
|
&SecurityDescriptor, 0))
|
||||||
{
|
{
|
||||||
Result = SvcInstanceAccessCheck(ClientToken, FILE_EXECUTE, Security);
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
if (!NT_SUCCESS(Result))
|
goto exit;
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result = SvcInstanceAccessCheck(ClientToken, SERVICE_START, SecurityDescriptor);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
ClassNameSize = (lstrlenW(ClassName) + 1) * sizeof(WCHAR);
|
ClassNameSize = (lstrlenW(ClassName) + 1) * sizeof(WCHAR);
|
||||||
InstanceNameSize = (lstrlenW(InstanceName) + 1) * sizeof(WCHAR);
|
InstanceNameSize = (lstrlenW(InstanceName) + 1) * sizeof(WCHAR);
|
||||||
|
|
||||||
@ -247,6 +248,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
memcpy(SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR), InstanceName, InstanceNameSize);
|
memcpy(SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR), InstanceName, InstanceNameSize);
|
||||||
SvcInstance->ClassName = SvcInstance->Buffer;
|
SvcInstance->ClassName = SvcInstance->Buffer;
|
||||||
SvcInstance->InstanceName = SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR);
|
SvcInstance->InstanceName = SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR);
|
||||||
|
SvcInstance->SecurityDescriptor = SecurityDescriptor;
|
||||||
|
|
||||||
if (L'\0' != CommandLine)
|
if (L'\0' != CommandLine)
|
||||||
{
|
{
|
||||||
@ -287,6 +289,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
exit:
|
exit:
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
|
LocalFree(SecurityDescriptor);
|
||||||
MemFree(SvcInstance->CommandLine);
|
MemFree(SvcInstance->CommandLine);
|
||||||
MemFree(SvcInstance);
|
MemFree(SvcInstance);
|
||||||
}
|
}
|
||||||
@ -309,6 +312,7 @@ VOID SvcInstanceDelete(SVC_INSTANCE *SvcInstance)
|
|||||||
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
||||||
if (0 != SvcInstance->Process)
|
if (0 != SvcInstance->Process)
|
||||||
CloseHandle(SvcInstance->Process);
|
CloseHandle(SvcInstance->Process);
|
||||||
|
LocalFree(SvcInstance->SecurityDescriptor);
|
||||||
MemFree(SvcInstance->CommandLine);
|
MemFree(SvcInstance->CommandLine);
|
||||||
MemFree(SvcInstance);
|
MemFree(SvcInstance);
|
||||||
}
|
}
|
||||||
@ -328,18 +332,39 @@ NTSTATUS SvcInstanceStart(HANDLE ClientToken,
|
|||||||
return SvcInstanceCreate(ClientToken, ClassName, InstanceName, Argc, Argv, &SvcInstance);
|
return SvcInstanceCreate(ClientToken, ClassName, InstanceName, Argc, Argv, &SvcInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID SvcInstanceStop(PWSTR InstanceName)
|
NTSTATUS SvcInstanceStop(HANDLE ClientToken, PWSTR InstanceName)
|
||||||
{
|
{
|
||||||
SVC_INSTANCE *SvcInstance;
|
SVC_INSTANCE *SvcInstance;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
EnterCriticalSection(&SvcInstanceLock);
|
EnterCriticalSection(&SvcInstanceLock);
|
||||||
|
|
||||||
SvcInstance = SvcInstanceFromName(InstanceName);
|
SvcInstance = SvcInstanceFromName(InstanceName);
|
||||||
if (0 != SvcInstance)
|
if (0 == SvcInstance)
|
||||||
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, SvcInstance->ProcessId);
|
{
|
||||||
|
Result = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = SvcInstanceAccessCheck(ClientToken, SERVICE_STOP, SvcInstance->SecurityDescriptor);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, SvcInstance->ProcessId))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(Result);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
LeaveCriticalSection(&SvcInstanceLock);
|
LeaveCriticalSection(&SvcInstanceLock);
|
||||||
|
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID SvcInstanceGetNameList(PWSTR Buffer, PULONG PSize)
|
NTSTATUS SvcInstanceGetNameList(HANDLE ClientToken, PWSTR Buffer, PULONG PSize)
|
||||||
{
|
{
|
||||||
SVC_INSTANCE *SvcInstance;
|
SVC_INSTANCE *SvcInstance;
|
||||||
PLIST_ENTRY ListEntry;
|
PLIST_ENTRY ListEntry;
|
||||||
@ -365,9 +390,11 @@ VOID SvcInstanceGetNameList(PWSTR Buffer, PULONG PSize)
|
|||||||
LeaveCriticalSection(&SvcInstanceLock);
|
LeaveCriticalSection(&SvcInstanceLock);
|
||||||
|
|
||||||
*PSize = (ULONG)(Buffer - BufferBeg);
|
*PSize = (ULONG)(Buffer - BufferBeg);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS SvcInstanceGetInfo(PWSTR InstanceName, PWSTR Buffer, PULONG PSize)
|
NTSTATUS SvcInstanceGetInfo(HANDLE ClientToken, PWSTR InstanceName, PWSTR Buffer, PULONG PSize)
|
||||||
{
|
{
|
||||||
SVC_INSTANCE *SvcInstance;
|
SVC_INSTANCE *SvcInstance;
|
||||||
ULONG ClassNameSize, InstanceNameSize, CommandLineSize;
|
ULONG ClassNameSize, InstanceNameSize, CommandLineSize;
|
||||||
@ -376,28 +403,36 @@ NTSTATUS SvcInstanceGetInfo(PWSTR InstanceName, PWSTR Buffer, PULONG PSize)
|
|||||||
EnterCriticalSection(&SvcInstanceLock);
|
EnterCriticalSection(&SvcInstanceLock);
|
||||||
|
|
||||||
SvcInstance = SvcInstanceFromName(InstanceName);
|
SvcInstance = SvcInstanceFromName(InstanceName);
|
||||||
if (0 != SvcInstance)
|
if (0 == SvcInstance)
|
||||||
{
|
{
|
||||||
ClassNameSize = lstrlenW(SvcInstance->ClassName) + 1;
|
|
||||||
InstanceNameSize = lstrlenW(SvcInstance->InstanceName) + 1;
|
|
||||||
CommandLineSize = lstrlenW(SvcInstance->CommandLine) + 1;
|
|
||||||
|
|
||||||
if (*PSize < (ClassNameSize + InstanceNameSize + CommandLineSize) * sizeof(WCHAR))
|
|
||||||
{
|
|
||||||
memcpy(Buffer, SvcInstance->ClassName,
|
|
||||||
ClassNameSize * sizeof(WCHAR));
|
|
||||||
memcpy(Buffer + ClassNameSize, SvcInstance->InstanceName,
|
|
||||||
InstanceNameSize * sizeof(WCHAR));
|
|
||||||
memcpy(Buffer + ClassNameSize + InstanceNameSize, SvcInstance->CommandLine,
|
|
||||||
CommandLineSize * sizeof(WCHAR));
|
|
||||||
Result = STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Result = STATUS_BUFFER_TOO_SMALL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Result = STATUS_OBJECT_NAME_NOT_FOUND;
|
Result = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = SvcInstanceAccessCheck(ClientToken, SERVICE_QUERY_STATUS, SvcInstance->SecurityDescriptor);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
ClassNameSize = lstrlenW(SvcInstance->ClassName) + 1;
|
||||||
|
InstanceNameSize = lstrlenW(SvcInstance->InstanceName) + 1;
|
||||||
|
CommandLineSize = lstrlenW(SvcInstance->CommandLine) + 1;
|
||||||
|
|
||||||
|
if (*PSize < (ClassNameSize + InstanceNameSize + CommandLineSize) * sizeof(WCHAR))
|
||||||
|
{
|
||||||
|
Result = STATUS_BUFFER_TOO_SMALL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(Buffer, SvcInstance->ClassName,
|
||||||
|
ClassNameSize * sizeof(WCHAR));
|
||||||
|
memcpy(Buffer + ClassNameSize, SvcInstance->InstanceName,
|
||||||
|
InstanceNameSize * sizeof(WCHAR));
|
||||||
|
memcpy(Buffer + ClassNameSize + InstanceNameSize, SvcInstance->CommandLine,
|
||||||
|
CommandLineSize * sizeof(WCHAR));
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
LeaveCriticalSection(&SvcInstanceLock);
|
LeaveCriticalSection(&SvcInstanceLock);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
@ -632,6 +667,17 @@ static inline PWSTR SvcPipeTransactGetPart(PWSTR *PP, PWSTR PipeBufEnd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline VOID SvcPipeTransactResult(NTSTATUS Result, PWSTR PipeBuf, PULONG PSize)
|
||||||
|
{
|
||||||
|
if (NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
*PipeBuf = L'$';
|
||||||
|
*PSize++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*PSize = wsprintfW(PipeBuf, L"!%08lx", FspNtStatusFromWin32(Result));
|
||||||
|
}
|
||||||
|
|
||||||
static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
||||||
{
|
{
|
||||||
if (sizeof(WCHAR) > *PSize)
|
if (sizeof(WCHAR) > *PSize)
|
||||||
@ -657,30 +703,22 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
|||||||
if (0 != ClassName && 0 != InstanceName)
|
if (0 != ClassName && 0 != InstanceName)
|
||||||
Result = SvcInstanceStart(ClientToken, ClassName, InstanceName, Argc, Argv);
|
Result = SvcInstanceStart(ClientToken, ClassName, InstanceName, Argc, Argv);
|
||||||
|
|
||||||
if (NT_SUCCESS(Result))
|
SvcPipeTransactResult(Result, PipeBuf, PSize);
|
||||||
{
|
|
||||||
*PipeBuf = L'$';
|
|
||||||
*PSize = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*PSize = wsprintfW(PipeBuf, L"!%08lx", FspNtStatusFromWin32(Result));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LauncherSvcInstanceStop:
|
case LauncherSvcInstanceStop:
|
||||||
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
|
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
|
||||||
if (0 != InstanceName)
|
if (0 != InstanceName)
|
||||||
SvcInstanceStop(InstanceName);
|
Result = SvcInstanceStop(ClientToken, InstanceName);
|
||||||
|
|
||||||
*PipeBuf = L'$';
|
SvcPipeTransactResult(Result, PipeBuf, PSize);
|
||||||
*PSize = 1;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LauncherSvcInstanceList:
|
case LauncherSvcInstanceList:
|
||||||
*PSize = PIPE_BUFFER_SIZE - 1;
|
*PSize = PIPE_BUFFER_SIZE - 1;
|
||||||
SvcInstanceGetNameList(PipeBuf + 1, PSize);
|
Result = SvcInstanceGetNameList(ClientToken, PipeBuf + 1, PSize);
|
||||||
|
|
||||||
*PipeBuf = L'$';
|
SvcPipeTransactResult(Result, PipeBuf, PSize);
|
||||||
*PSize++;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LauncherSvcInstanceInfo:
|
case LauncherSvcInstanceInfo:
|
||||||
@ -690,16 +728,10 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
|||||||
if (0 != InstanceName)
|
if (0 != InstanceName)
|
||||||
{
|
{
|
||||||
*PSize = PIPE_BUFFER_SIZE - 1;
|
*PSize = PIPE_BUFFER_SIZE - 1;
|
||||||
Result = SvcInstanceGetInfo(InstanceName, PipeBuf + 1, PSize);
|
Result = SvcInstanceGetInfo(ClientToken, InstanceName, PipeBuf + 1, PSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NT_SUCCESS(Result))
|
SvcPipeTransactResult(Result, PipeBuf, PSize);
|
||||||
{
|
|
||||||
*PipeBuf = L'$';
|
|
||||||
*PSize++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*PSize = wsprintfW(PipeBuf, L"!%08lx", FspNtStatusFromWin32(Result));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
#define PIPE_BUFFER_SIZE 2048
|
#define PIPE_BUFFER_SIZE 2048
|
||||||
#define PIPE_DEFAULT_TIMEOUT 3000
|
#define PIPE_DEFAULT_TIMEOUT 3000
|
||||||
|
|
||||||
|
#define SVC_INSTANCE_DEFAULT_SDDL "O:SYG:SYD:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)"
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
LauncherSvcInstanceStart = 'S',
|
LauncherSvcInstanceStart = 'S',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user