launcher: access control

This commit is contained in:
Bill Zissimopoulos 2016-05-12 13:44:07 -07:00
parent ceef2bf55e
commit 6971f4d6ae
2 changed files with 99 additions and 65 deletions

View File

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

View File

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