launcher, launchctl: testing

This commit is contained in:
Bill Zissimopoulos 2016-05-12 22:11:28 -07:00
parent 22c324de69
commit da85f2aa08
3 changed files with 77 additions and 51 deletions

View File

@ -54,9 +54,9 @@ static void usage(void)
"\n" "\n"
"commands:\n" "commands:\n"
" start ClassName InstanceName Args...\n" " start ClassName InstanceName Args...\n"
" stop InstanceName\n" " stop ClassName InstanceName\n"
" list\n" " list\n"
" info\n", " info ClassName InstanceName\n",
PROGNAME); PROGNAME);
} }
@ -105,8 +105,8 @@ int start(PWSTR PipeBuf, ULONG PipeBufSize,
ClassNameSize = lstrlenW(ClassName) + 1; ClassNameSize = lstrlenW(ClassName) + 1;
InstanceNameSize = lstrlenW(InstanceName) + 1; InstanceNameSize = lstrlenW(InstanceName) + 1;
ArgvSize = 0; ArgvSize = 0;
for (DWORD Argi = Argc; Argc > Argi; Argi++) for (DWORD Argi = 0; Argc > Argi; Argi++)
ArgvSize += lstrlenW(Argv[Argi]); ArgvSize += lstrlenW(Argv[Argi]) + 1;
if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize + ArgvSize) * sizeof(WCHAR)) if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize + ArgvSize) * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
@ -115,9 +115,9 @@ int start(PWSTR PipeBuf, ULONG PipeBufSize,
*P++ = LauncherSvcInstanceStart; *P++ = LauncherSvcInstanceStart;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize; memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize; memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
for (DWORD Argi = Argc; Argc > Argi; Argi++) for (DWORD Argi = 0; Argc > Argi; Argi++)
{ {
ArgvSize = lstrlenW(Argv[Argi]); ArgvSize = lstrlenW(Argv[Argi]) + 1;
memcpy(P, Argv[Argi], ArgvSize * sizeof(WCHAR)); P += ArgvSize; memcpy(P, Argv[Argi], ArgvSize * sizeof(WCHAR)); P += ArgvSize;
} }
@ -135,20 +135,22 @@ int start(PWSTR PipeBuf, ULONG PipeBufSize,
} }
int stop(PWSTR PipeBuf, ULONG PipeBufSize, int stop(PWSTR PipeBuf, ULONG PipeBufSize,
PWSTR InstanceName) PWSTR ClassName, PWSTR InstanceName)
{ {
PWSTR P; PWSTR P;
DWORD InstanceNameSize; DWORD ClassNameSize, InstanceNameSize;
DWORD LastError, BytesTransferred; DWORD LastError, BytesTransferred;
ClassNameSize = lstrlenW(ClassName) + 1;
InstanceNameSize = lstrlenW(InstanceName) + 1; InstanceNameSize = lstrlenW(InstanceName) + 1;
if (PipeBufSize < (1 + InstanceNameSize) * sizeof(WCHAR)) if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize) * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
P = PipeBuf; P = PipeBuf;
*P++ = LauncherSvcInstanceStop; *P++ = LauncherSvcInstanceStop;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
if (CallNamedPipeW(L"" PIPE_NAME, if (CallNamedPipeW(L"" PIPE_NAME,
PipeBuf, (DWORD)((P - PipeBuf) * sizeof(WCHAR)), PipeBuf, PipeBufSize, PipeBuf, (DWORD)((P - PipeBuf) * sizeof(WCHAR)), PipeBuf, PipeBufSize,
@ -188,20 +190,22 @@ int list(PWSTR PipeBuf, ULONG PipeBufSize)
} }
int info(PWSTR PipeBuf, ULONG PipeBufSize, int info(PWSTR PipeBuf, ULONG PipeBufSize,
PWSTR InstanceName) PWSTR ClassName, PWSTR InstanceName)
{ {
PWSTR P; PWSTR P;
DWORD InstanceNameSize; DWORD ClassNameSize, InstanceNameSize;
DWORD LastError, BytesTransferred; DWORD LastError, BytesTransferred;
ClassNameSize = lstrlenW(ClassName) + 1;
InstanceNameSize = lstrlenW(InstanceName) + 1; InstanceNameSize = lstrlenW(InstanceName) + 1;
if (PipeBufSize < (1 + InstanceNameSize) * sizeof(WCHAR)) if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize) * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
P = PipeBuf; P = PipeBuf;
*P++ = LauncherSvcInstanceInfo; *P++ = LauncherSvcInstanceInfo;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
if (CallNamedPipeW(L"" PIPE_NAME, if (CallNamedPipeW(L"" PIPE_NAME,
PipeBuf, (DWORD)((P - PipeBuf) * sizeof(WCHAR)), PipeBuf, PipeBufSize, PipeBuf, (DWORD)((P - PipeBuf) * sizeof(WCHAR)), PipeBuf, PipeBufSize,
@ -231,7 +235,7 @@ int wmain(int argc, wchar_t **argv)
if (0 == argc) if (0 == argc)
usage(); usage();
if (0 == lstrcmp(L"start", argv[0])) if (0 == lstrcmpW(L"start", argv[0]))
{ {
if (3 > argc || argc > 12) if (3 > argc || argc > 12)
usage(); usage();
@ -239,26 +243,28 @@ int wmain(int argc, wchar_t **argv)
return start(PipeBuf, PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3); return start(PipeBuf, PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3);
} }
else else
if (0 == lstrcmp(L"stop", argv[0])) if (0 == lstrcmpW(L"stop", argv[0]))
{ {
if (2 != argc) if (3 != argc)
usage(); usage();
return stop(PipeBuf, PIPE_BUFFER_SIZE, argv[1]); return stop(PipeBuf, PIPE_BUFFER_SIZE, argv[1], argv[2]);
} }
if (0 == lstrcmp(L"list", argv[0])) else
if (0 == lstrcmpW(L"list", argv[0]))
{ {
if (1 != argc) if (1 != argc)
usage(); usage();
return list(PipeBuf, PIPE_BUFFER_SIZE); return list(PipeBuf, PIPE_BUFFER_SIZE);
} }
if (0 == lstrcmp(L"info", argv[0])) else
if (0 == lstrcmpW(L"info", argv[0]))
{ {
if (2 != argc) if (3 != argc)
usage(); usage();
return info(PipeBuf, PIPE_BUFFER_SIZE, argv[1]); return info(PipeBuf, PIPE_BUFFER_SIZE, argv[1], argv[2]);
} }
else else
usage(); usage();

View File

@ -18,7 +18,7 @@
#include <launcher/launcher.h> #include <launcher/launcher.h>
#include <sddl.h> #include <sddl.h>
#define PROGNAME "WinFsp-Launcher" #define PROGNAME "WinFsp.Launcher"
#define REGKEY "SYSTEM\\CurrentControlSet\\Services\\" PROGNAME "\\Services" #define REGKEY "SYSTEM\\CurrentControlSet\\Services\\" PROGNAME "\\Services"
typedef struct typedef struct
@ -39,7 +39,7 @@ static LIST_ENTRY SvcInstanceList = { &SvcInstanceList, &SvcInstanceList };
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Fired); static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Fired);
static SVC_INSTANCE *SvcInstanceFromName(PWSTR InstanceName) static SVC_INSTANCE *SvcInstanceLookup(PWSTR ClassName, PWSTR InstanceName)
{ {
SVC_INSTANCE *SvcInstance; SVC_INSTANCE *SvcInstance;
PLIST_ENTRY ListEntry; PLIST_ENTRY ListEntry;
@ -50,7 +50,8 @@ static SVC_INSTANCE *SvcInstanceFromName(PWSTR InstanceName)
{ {
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry); SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
if (0 == lstrcmpW(InstanceName, SvcInstance->InstanceName)) if (0 == lstrcmpW(ClassName, SvcInstance->ClassName) &&
0 == lstrcmpW(InstanceName, SvcInstance->InstanceName))
return SvcInstance; return SvcInstance;
} }
@ -174,7 +175,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
EnterCriticalSection(&SvcInstanceLock); EnterCriticalSection(&SvcInstanceLock);
if (0 != SvcInstanceFromName(InstanceName)) if (0 != SvcInstanceLookup(ClassName, InstanceName))
{ {
Result = STATUS_OBJECT_NAME_COLLISION; Result = STATUS_OBJECT_NAME_COLLISION;
goto exit; goto exit;
@ -295,8 +296,11 @@ exit:
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
LocalFree(SecurityDescriptor); LocalFree(SecurityDescriptor);
MemFree(SvcInstance->CommandLine); if (0 != SvcInstance)
MemFree(SvcInstance); {
MemFree(SvcInstance->CommandLine);
MemFree(SvcInstance);
}
} }
if (0 != RegKey) if (0 != RegKey)
@ -337,14 +341,15 @@ NTSTATUS SvcInstanceStart(HANDLE ClientToken,
return SvcInstanceCreate(ClientToken, ClassName, InstanceName, Argc, Argv, &SvcInstance); return SvcInstanceCreate(ClientToken, ClassName, InstanceName, Argc, Argv, &SvcInstance);
} }
NTSTATUS SvcInstanceStop(HANDLE ClientToken, PWSTR InstanceName) NTSTATUS SvcInstanceStop(HANDLE ClientToken,
PWSTR ClassName, PWSTR InstanceName)
{ {
SVC_INSTANCE *SvcInstance; SVC_INSTANCE *SvcInstance;
NTSTATUS Result; NTSTATUS Result;
EnterCriticalSection(&SvcInstanceLock); EnterCriticalSection(&SvcInstanceLock);
SvcInstance = SvcInstanceFromName(InstanceName); SvcInstance = SvcInstanceLookup(ClassName, InstanceName);
if (0 == SvcInstance) if (0 == SvcInstance)
{ {
Result = STATUS_OBJECT_NAME_NOT_FOUND; Result = STATUS_OBJECT_NAME_NOT_FOUND;
@ -369,12 +374,13 @@ exit:
return Result; return Result;
} }
NTSTATUS SvcInstanceGetNameList(HANDLE ClientToken, PWSTR Buffer, PULONG PSize) NTSTATUS SvcInstanceGetNameList(HANDLE ClientToken,
PWSTR Buffer, PULONG PSize)
{ {
SVC_INSTANCE *SvcInstance; SVC_INSTANCE *SvcInstance;
PLIST_ENTRY ListEntry; PLIST_ENTRY ListEntry;
PWSTR BufferBeg = Buffer, BufferEnd = Buffer + *PSize / sizeof(WCHAR); PWSTR P = Buffer, BufferEnd = P + *PSize / sizeof(WCHAR);
ULONG InstanceNameSize; ULONG ClassNameSize, InstanceNameSize;
EnterCriticalSection(&SvcInstanceLock); EnterCriticalSection(&SvcInstanceLock);
@ -384,22 +390,26 @@ NTSTATUS SvcInstanceGetNameList(HANDLE ClientToken, PWSTR Buffer, PULONG PSize)
{ {
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry); SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
ClassNameSize = lstrlenW(SvcInstance->ClassName) + 1;
InstanceNameSize = lstrlenW(SvcInstance->InstanceName) + 1; InstanceNameSize = lstrlenW(SvcInstance->InstanceName) + 1;
if (BufferEnd < Buffer + InstanceNameSize)
if (BufferEnd < P + ClassNameSize + InstanceNameSize)
break; break;
memcpy(Buffer, SvcInstance->InstanceName, InstanceNameSize * sizeof(WCHAR)); memcpy(P, SvcInstance->ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
Buffer += InstanceNameSize; *Buffer++ = L' ';
memcpy(P, SvcInstance->InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
} }
LeaveCriticalSection(&SvcInstanceLock); LeaveCriticalSection(&SvcInstanceLock);
*PSize = (ULONG)(Buffer - BufferBeg); *PSize = (ULONG)(P - Buffer);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS SvcInstanceGetInfo(HANDLE ClientToken, PWSTR InstanceName, PWSTR Buffer, PULONG PSize) NTSTATUS SvcInstanceGetInfo(HANDLE ClientToken,
PWSTR ClassName, PWSTR InstanceName, PWSTR Buffer, PULONG PSize)
{ {
SVC_INSTANCE *SvcInstance; SVC_INSTANCE *SvcInstance;
ULONG ClassNameSize, InstanceNameSize, CommandLineSize; ULONG ClassNameSize, InstanceNameSize, CommandLineSize;
@ -407,7 +417,7 @@ NTSTATUS SvcInstanceGetInfo(HANDLE ClientToken, PWSTR InstanceName, PWSTR Buffer
EnterCriticalSection(&SvcInstanceLock); EnterCriticalSection(&SvcInstanceLock);
SvcInstance = SvcInstanceFromName(InstanceName); SvcInstance = SvcInstanceLookup(ClassName, InstanceName);
if (0 == SvcInstance) if (0 == SvcInstance)
{ {
Result = STATUS_OBJECT_NAME_NOT_FOUND; Result = STATUS_OBJECT_NAME_NOT_FOUND;
@ -476,7 +486,7 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
PIPE_ACCESS_DUPLEX | PIPE_ACCESS_DUPLEX |
FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
1, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, PIPE_DEFAULT_TIMEOUT, 0); 1, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, PIPE_DEFAULT_TIMEOUT, &SecurityAttributes);
if (INVALID_HANDLE_VALUE == SvcPipe) if (INVALID_HANDLE_VALUE == SvcPipe)
goto fail; goto fail;
@ -582,7 +592,8 @@ static DWORD WINAPI SvcPipeServer(PVOID Context)
SvcEvent, SvcPipe, &SvcOverlapped, &BytesTransferred); SvcEvent, SvcPipe, &SvcOverlapped, &BytesTransferred);
if (-1 == LastError) if (-1 == LastError)
break; break;
else if (ERROR_PIPE_CONNECTED != LastError && ERROR_NO_DATA != LastError) else if (0 != LastError &&
ERROR_PIPE_CONNECTED != LastError && ERROR_NO_DATA != LastError)
{ {
FspServiceLog(EVENTLOG_WARNING_TYPE, LoopWarningMessage, FspServiceLog(EVENTLOG_WARNING_TYPE, LoopWarningMessage,
L"ConnectNamedPipe", LastError); L"ConnectNamedPipe", LastError);
@ -594,7 +605,7 @@ static DWORD WINAPI SvcPipeServer(PVOID Context)
SvcEvent, SvcPipe, &SvcOverlapped, &BytesTransferred); SvcEvent, SvcPipe, &SvcOverlapped, &BytesTransferred);
if (-1 == LastError) if (-1 == LastError)
break; break;
else if (0 != LastError || sizeof(WCHAR) <= BytesTransferred) else if (0 != LastError || sizeof(WCHAR) > BytesTransferred)
{ {
DisconnectNamedPipe(SvcPipe); DisconnectNamedPipe(SvcPipe);
if (0 != LastError) if (0 != LastError)
@ -679,7 +690,7 @@ static inline VOID SvcPipeTransactResult(NTSTATUS Result, PWSTR PipeBuf, PULONG
if (NT_SUCCESS(Result)) if (NT_SUCCESS(Result))
{ {
*PipeBuf = L'$'; *PipeBuf = L'$';
*PSize++; (*PSize)++;
} }
else else
*PSize = wsprintfW(PipeBuf, L"!%08lx", FspNtStatusFromWin32(Result)); *PSize = wsprintfW(PipeBuf, L"!%08lx", FspNtStatusFromWin32(Result));
@ -706,7 +717,7 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
if (0 == (Argv[Argc] = SvcPipeTransactGetPart(&P, PipeBufEnd))) if (0 == (Argv[Argc] = SvcPipeTransactGetPart(&P, PipeBufEnd)))
break; break;
Result = STATUS_UNSUCCESSFUL; Result = STATUS_INVALID_PARAMETER;
if (0 != ClassName && 0 != InstanceName) if (0 != ClassName && 0 != InstanceName)
Result = SvcInstanceStart(ClientToken, ClassName, InstanceName, Argc, Argv); Result = SvcInstanceStart(ClientToken, ClassName, InstanceName, Argc, Argv);
@ -714,9 +725,12 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
break; break;
case LauncherSvcInstanceStop: case LauncherSvcInstanceStop:
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd); InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
Result = STATUS_INVALID_PARAMETER;
if (0 != InstanceName) if (0 != InstanceName)
Result = SvcInstanceStop(ClientToken, InstanceName); Result = SvcInstanceStop(ClientToken, ClassName, InstanceName);
SvcPipeTransactResult(Result, PipeBuf, PSize); SvcPipeTransactResult(Result, PipeBuf, PSize);
break; break;
@ -729,19 +743,21 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
break; break;
case LauncherSvcInstanceInfo: case LauncherSvcInstanceInfo:
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd); InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
Result = STATUS_UNSUCCESSFUL; Result = STATUS_INVALID_PARAMETER;
if (0 != InstanceName) if (0 != InstanceName)
{ {
*PSize = PIPE_BUFFER_SIZE - 1; *PSize = PIPE_BUFFER_SIZE - 1;
Result = SvcInstanceGetInfo(ClientToken, InstanceName, PipeBuf + 1, PSize); Result = SvcInstanceGetInfo(ClientToken, ClassName, InstanceName, PipeBuf + 1, PSize);
} }
SvcPipeTransactResult(Result, PipeBuf, PSize); SvcPipeTransactResult(Result, PipeBuf, PSize);
break; break;
default: default:
SvcPipeTransactResult(STATUS_INVALID_PARAMETER, PipeBuf, PSize);
break; break;
} }
} }

View File

@ -27,11 +27,15 @@
/* /*
* The launcher named pipe SDDL gives full access to LocalSystem and Administrators. * The launcher named pipe SDDL gives full access to LocalSystem and Administrators.
* It also gives generic read access and FILE_WRITE_DATA (DC) to Everyone. Note that * It also gives GENERIC_READ and GENERIC_WRITE access to Everyone. This includes the
* we cannot give generic write access or equivalently FILE_GENERIC_WRITE (FW) because * FILE_CREATE_PIPE_INSTANCE right which should not normally be granted to any process
* we would also grant the FILE_CREATE_PIPE_INSTANCE right. * that is not the pipe server. The reason that the GENERIC_WRITE is required is to allow
* clients to use CallNamedPipeW which opens the pipe handle using CreateFileW and the
* GENERIC_READ | GENERIC_WRITE access right. The reason that it should be safe to grant
* the FILE_CREATE_PIPE_INSTANCE right is that the server creates the named pipe with
* MaxInstances == 1 (and therefore no client can create additional instances).
*/ */
#define PIPE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRDC;;;WD)" #define PIPE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW;;;WD)"
/* /*
* The default service instance SDDL gives full access to LocalSystem and Administrators. * The default service instance SDDL gives full access to LocalSystem and Administrators.