mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 11:38:39 -05:00 
			
		
		
		
	launcher: access control
This commit is contained in:
		| @@ -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) | ||||||
|     { |     { | ||||||
|  |         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; |     ClassNameSize = lstrlenW(SvcInstance->ClassName) + 1; | ||||||
|     InstanceNameSize = lstrlenW(SvcInstance->InstanceName) + 1; |     InstanceNameSize = lstrlenW(SvcInstance->InstanceName) + 1; | ||||||
|     CommandLineSize = lstrlenW(SvcInstance->CommandLine) + 1; |     CommandLineSize = lstrlenW(SvcInstance->CommandLine) + 1; | ||||||
|  |  | ||||||
|     if (*PSize < (ClassNameSize + InstanceNameSize + CommandLineSize) * sizeof(WCHAR)) |     if (*PSize < (ClassNameSize + InstanceNameSize + CommandLineSize) * sizeof(WCHAR)) | ||||||
|     { |     { | ||||||
|  |         Result = STATUS_BUFFER_TOO_SMALL; | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     memcpy(Buffer, SvcInstance->ClassName, |     memcpy(Buffer, SvcInstance->ClassName, | ||||||
|         ClassNameSize * sizeof(WCHAR)); |         ClassNameSize * sizeof(WCHAR)); | ||||||
|     memcpy(Buffer + ClassNameSize, SvcInstance->InstanceName, |     memcpy(Buffer + ClassNameSize, SvcInstance->InstanceName, | ||||||
|         InstanceNameSize * sizeof(WCHAR)); |         InstanceNameSize * sizeof(WCHAR)); | ||||||
|     memcpy(Buffer + ClassNameSize + InstanceNameSize, SvcInstance->CommandLine, |     memcpy(Buffer + ClassNameSize + InstanceNameSize, SvcInstance->CommandLine, | ||||||
|         CommandLineSize * sizeof(WCHAR)); |         CommandLineSize * sizeof(WCHAR)); | ||||||
|             Result = STATUS_SUCCESS; |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|             Result = STATUS_BUFFER_TOO_SMALL; |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|         Result = STATUS_OBJECT_NAME_NOT_FOUND; |  | ||||||
|  |  | ||||||
|  |     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', | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user