mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -05:00
launcher: Stderr registry setting
This commit adds a new Stderr registry setting that can be used to redirect the standard error output of a launched service instance.
This commit is contained in:
parent
3eb115eb22
commit
01744e8193
@ -287,7 +287,8 @@ typedef struct _FSP_LAUNCH_REG_RECORD
|
|||||||
PWSTR RunAs;
|
PWSTR RunAs;
|
||||||
PWSTR Security;
|
PWSTR Security;
|
||||||
PWSTR AuthPackage;
|
PWSTR AuthPackage;
|
||||||
PVOID Reserved0[5];
|
PWSTR Stderr;
|
||||||
|
PVOID Reserved0[4];
|
||||||
ULONG JobControl;
|
ULONG JobControl;
|
||||||
ULONG Credentials;
|
ULONG Credentials;
|
||||||
ULONG AuthPackageId;
|
ULONG AuthPackageId;
|
||||||
|
@ -271,6 +271,7 @@ FSP_API NTSTATUS FspLaunchRegSetRecord(
|
|||||||
SETFIELD(RunAs);
|
SETFIELD(RunAs);
|
||||||
SETFIELD(Security);
|
SETFIELD(Security);
|
||||||
SETFIELD(AuthPackage);
|
SETFIELD(AuthPackage);
|
||||||
|
SETFIELD(Stderr);
|
||||||
SETFIELDI(JobControl, ~0); /* JobControl default is 1; but we treat as without default */
|
SETFIELDI(JobControl, ~0); /* JobControl default is 1; but we treat as without default */
|
||||||
SETFIELDI(Credentials, 0);
|
SETFIELDI(Credentials, 0);
|
||||||
SETFIELDI(AuthPackageId, 0);
|
SETFIELDI(AuthPackageId, 0);
|
||||||
@ -424,6 +425,7 @@ FSP_API NTSTATUS FspLaunchRegGetRecord(
|
|||||||
GETFIELD(RunAs);
|
GETFIELD(RunAs);
|
||||||
GETFIELD(Security);
|
GETFIELD(Security);
|
||||||
GETFIELD(AuthPackage);
|
GETFIELD(AuthPackage);
|
||||||
|
GETFIELD(Stderr);
|
||||||
GETFIELDI(JobControl);
|
GETFIELDI(JobControl);
|
||||||
GETFIELDI(Credentials);
|
GETFIELDI(Credentials);
|
||||||
GETFIELDI(AuthPackageId);
|
GETFIELDI(AuthPackageId);
|
||||||
@ -458,6 +460,8 @@ FSP_API NTSTATUS FspLaunchRegGetRecord(
|
|||||||
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.Security - RegBuf)) : 0;
|
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.Security - RegBuf)) : 0;
|
||||||
Record->AuthPackage = 0 != RecordBuf.AuthPackage ?
|
Record->AuthPackage = 0 != RecordBuf.AuthPackage ?
|
||||||
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.AuthPackage - RegBuf)) : 0;
|
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.AuthPackage - RegBuf)) : 0;
|
||||||
|
Record->Stderr = 0 != RecordBuf.Stderr ?
|
||||||
|
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.Stderr - RegBuf)) : 0;
|
||||||
Record->JobControl = RecordBuf.JobControl;
|
Record->JobControl = RecordBuf.JobControl;
|
||||||
Record->Credentials = RecordBuf.Credentials;
|
Record->Credentials = RecordBuf.Credentials;
|
||||||
Record->AuthPackageId = RecordBuf.AuthPackageId;
|
Record->AuthPackageId = RecordBuf.AuthPackageId;
|
||||||
|
@ -464,7 +464,7 @@ typedef struct
|
|||||||
DWORD ProcessId;
|
DWORD ProcessId;
|
||||||
HANDLE Process;
|
HANDLE Process;
|
||||||
HANDLE ProcessWait;
|
HANDLE ProcessWait;
|
||||||
HANDLE StdioHandles[2];
|
HANDLE StdioHandles[3];
|
||||||
DWORD Recovery;
|
DWORD Recovery;
|
||||||
ULONG Argc;
|
ULONG Argc;
|
||||||
PWSTR *Argv;
|
PWSTR *Argv;
|
||||||
@ -502,27 +502,28 @@ static SVC_INSTANCE *SvcInstanceLookup(PWSTR ClassName, PWSTR InstanceName)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ULONG SvcInstanceArgumentLength(PWSTR Arg, PWSTR Pattern)
|
static inline ULONG SvcInstanceArgumentLength(PWSTR Arg, PWSTR Pattern, BOOLEAN Quote)
|
||||||
{
|
{
|
||||||
PWSTR PathTransform(PWSTR Dest, PWSTR Arg, PWSTR Pattern);
|
PWSTR PathTransform(PWSTR Dest, PWSTR Arg, PWSTR Pattern);
|
||||||
|
|
||||||
return 2 + (ULONG)(UINT_PTR)PathTransform(0, Arg, Pattern);
|
return (Quote ? 2 : 0) + (ULONG)((UINT_PTR)PathTransform(0, Arg, Pattern) / sizeof(WCHAR));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline PWSTR SvcInstanceArgumentCopy(PWSTR Dest, PWSTR Arg, PWSTR Pattern)
|
static inline PWSTR SvcInstanceArgumentCopy(PWSTR Dest, PWSTR Arg, PWSTR Pattern, BOOLEAN Quote)
|
||||||
{
|
{
|
||||||
PWSTR PathTransform(PWSTR Dest, PWSTR Arg, PWSTR Pattern);
|
PWSTR PathTransform(PWSTR Dest, PWSTR Arg, PWSTR Pattern);
|
||||||
|
|
||||||
|
if (Quote)
|
||||||
*Dest++ = L'"';
|
*Dest++ = L'"';
|
||||||
Dest = PathTransform(Dest, Arg, Pattern);
|
Dest = PathTransform(Dest, Arg, Pattern);
|
||||||
|
if (Quote)
|
||||||
*Dest++ = L'"';
|
*Dest++ = L'"';
|
||||||
|
|
||||||
return Dest;
|
return Dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS SvcInstanceReplaceArguments(PWSTR String,
|
static NTSTATUS SvcInstanceReplaceArguments(PWSTR String,
|
||||||
ULONG Argc, PWSTR *Argv,
|
ULONG Argc, PWSTR *Argv, PWSTR *Varv, BOOLEAN Quote,
|
||||||
PWSTR UserName,
|
|
||||||
PWSTR *PNewString)
|
PWSTR *PNewString)
|
||||||
{
|
{
|
||||||
PWSTR NewString = 0, P, Q;
|
PWSTR NewString = 0, P, Q;
|
||||||
@ -544,24 +545,24 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String,
|
|||||||
{
|
{
|
||||||
Pattern = ++P;
|
Pattern = ++P;
|
||||||
while (!(L'\0' == *P ||
|
while (!(L'\0' == *P ||
|
||||||
(L'0' <= *P && *P <= '9') ||
|
(L'0' <= *P && *P <= L'9') ||
|
||||||
(L'A' <= *P && *P <= 'Z')))
|
(L'A' <= *P && *P <= L'Z')))
|
||||||
P++;
|
P++;
|
||||||
}
|
}
|
||||||
if (L'0' <= *P && *P <= '9')
|
if (L'0' <= *P && *P <= L'9')
|
||||||
{
|
{
|
||||||
if (Argc > (ULONG)(*P - L'0'))
|
if (Argc > (ULONG)(*P - L'0'))
|
||||||
Length += SvcInstanceArgumentLength(Argv[*P - L'0'], Pattern);
|
Length += SvcInstanceArgumentLength(Argv[*P - L'0'], Pattern, Quote);
|
||||||
else
|
else
|
||||||
Length += SvcInstanceArgumentLength(EmptyArg, 0);
|
Length += SvcInstanceArgumentLength(EmptyArg, 0, Quote);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (L'U' == *P)
|
if (L'A' <= *P && *P <= L'Z')
|
||||||
{
|
{
|
||||||
if (0 != UserName)
|
if (0 != Varv[*P - L'A'])
|
||||||
Length += SvcInstanceArgumentLength(UserName, Pattern);
|
Length += SvcInstanceArgumentLength(Varv[*P - L'A'], Pattern, Quote);
|
||||||
else
|
else
|
||||||
Length += SvcInstanceArgumentLength(EmptyArg, 0);
|
Length += SvcInstanceArgumentLength(EmptyArg, 0, Quote);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (*P)
|
if (*P)
|
||||||
@ -590,24 +591,24 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String,
|
|||||||
{
|
{
|
||||||
Pattern = ++P;
|
Pattern = ++P;
|
||||||
while (!(L'\0' == *P ||
|
while (!(L'\0' == *P ||
|
||||||
(L'0' <= *P && *P <= '9') ||
|
(L'0' <= *P && *P <= L'9') ||
|
||||||
(L'A' <= *P && *P <= 'Z')))
|
(L'A' <= *P && *P <= L'Z')))
|
||||||
P++;
|
P++;
|
||||||
}
|
}
|
||||||
if (L'0' <= *P && *P <= '9')
|
if (L'0' <= *P && *P <= L'9')
|
||||||
{
|
{
|
||||||
if (Argc > (ULONG)(*P - L'0'))
|
if (Argc > (ULONG)(*P - L'0'))
|
||||||
Q = SvcInstanceArgumentCopy(Q, Argv[*P - L'0'], Pattern);
|
Q = SvcInstanceArgumentCopy(Q, Argv[*P - L'0'], Pattern, Quote);
|
||||||
else
|
else
|
||||||
Q = SvcInstanceArgumentCopy(Q, EmptyArg, 0);
|
Q = SvcInstanceArgumentCopy(Q, EmptyArg, 0, Quote);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (L'U' == *P)
|
if (L'A' <= *P && *P <= L'Z')
|
||||||
{
|
{
|
||||||
if (0 != UserName)
|
if (0 != Varv[*P - L'A'])
|
||||||
Q = SvcInstanceArgumentCopy(Q, UserName, Pattern);
|
Q = SvcInstanceArgumentCopy(Q, Varv[*P - L'A'], Pattern, Quote);
|
||||||
else
|
else
|
||||||
Q = SvcInstanceArgumentCopy(Q, EmptyArg, 0);
|
Q = SvcInstanceArgumentCopy(Q, EmptyArg, 0, Quote);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (*P)
|
if (*P)
|
||||||
@ -718,14 +719,15 @@ static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
|
|||||||
|
|
||||||
static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
||||||
PWSTR Executable, PWSTR CommandLine, PWSTR WorkDirectory,
|
PWSTR Executable, PWSTR CommandLine, PWSTR WorkDirectory,
|
||||||
HANDLE StdioHandles[2],
|
HANDLE StdioHandles[2], HANDLE StderrHandle,
|
||||||
PPROCESS_INFORMATION ProcessInfo)
|
PPROCESS_INFORMATION ProcessInfo)
|
||||||
{
|
{
|
||||||
WCHAR WorkDirectoryBuf[MAX_PATH];
|
WCHAR WorkDirectoryBuf[MAX_PATH];
|
||||||
STARTUPINFOEXW StartupInfoEx;
|
STARTUPINFOEXW StartupInfoEx;
|
||||||
HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0/* DO NOT CLOSE!*/ };
|
HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE/* NO CLOSE!*/ };
|
||||||
HANDLE ParentHandles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
|
HANDLE ParentHandles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
|
||||||
PPROC_THREAD_ATTRIBUTE_LIST AttrList = 0;
|
PPROC_THREAD_ATTRIBUTE_LIST AttrList = 0;
|
||||||
|
BOOLEAN InitDoneAttrList = FALSE;
|
||||||
SIZE_T Size;
|
SIZE_T Size;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
@ -748,7 +750,7 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
|||||||
memset(&StartupInfoEx, 0, sizeof StartupInfoEx);
|
memset(&StartupInfoEx, 0, sizeof StartupInfoEx);
|
||||||
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
|
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
|
||||||
|
|
||||||
if (0 != StdioHandles)
|
if (0 != StdioHandles || INVALID_HANDLE_VALUE != StderrHandle)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Create child process and redirect stdin/stdout. Do *not* inherit other handles.
|
* Create child process and redirect stdin/stdout. Do *not* inherit other handles.
|
||||||
@ -757,6 +759,8 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
|||||||
* https://blogs.msdn.microsoft.com/oldnewthing/20111216-00/?p=8873/
|
* https://blogs.msdn.microsoft.com/oldnewthing/20111216-00/?p=8873/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (0 != StdioHandles)
|
||||||
|
{
|
||||||
/* create stdin read/write ends; make them inheritable */
|
/* create stdin read/write ends; make them inheritable */
|
||||||
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0],
|
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0],
|
||||||
0, TRUE, FALSE, 0, 0))
|
0, TRUE, FALSE, 0, 0))
|
||||||
@ -764,7 +768,10 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
|||||||
Result = FspNtStatusFromWin32(GetLastError());
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != StdioHandles)
|
||||||
|
{
|
||||||
/* create stdout read/write ends; make them inheritable */
|
/* create stdout read/write ends; make them inheritable */
|
||||||
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1],
|
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1],
|
||||||
0, FALSE, TRUE, FILE_FLAG_OVERLAPPED, 0))
|
0, FALSE, TRUE, FILE_FLAG_OVERLAPPED, 0))
|
||||||
@ -772,8 +779,10 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
|||||||
Result = FspNtStatusFromWin32(GetLastError());
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ChildHandles[2] = GetStdHandle(STD_ERROR_HANDLE);
|
if (INVALID_HANDLE_VALUE != StderrHandle)
|
||||||
|
ChildHandles[2] = StderrHandle;
|
||||||
|
|
||||||
Size = 0;
|
Size = 0;
|
||||||
if (!InitializeProcThreadAttributeList(0, 1, 0, &Size) &&
|
if (!InitializeProcThreadAttributeList(0, 1, 0, &Size) &&
|
||||||
@ -795,10 +804,14 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
|||||||
Result = FspNtStatusFromWin32(GetLastError());
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
InitDoneAttrList = TRUE;
|
||||||
|
|
||||||
/* only the child ends of stdin/stdout are actually inherited */
|
/* only the child ends of stdin/stdout/stderr are actually inherited */
|
||||||
if (!UpdateProcThreadAttribute(AttrList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
|
if (!UpdateProcThreadAttribute(AttrList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
|
||||||
ChildHandles, sizeof ChildHandles, 0, 0))
|
0 != StdioHandles ? ChildHandles : ChildHandles + 2,
|
||||||
|
((0 != StdioHandles ? 2 : 0) + (INVALID_HANDLE_VALUE != StderrHandle ? 1 : 0)) *
|
||||||
|
sizeof ChildHandles[0],
|
||||||
|
0, 0))
|
||||||
{
|
{
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
goto exit;
|
goto exit;
|
||||||
@ -877,6 +890,8 @@ exit:
|
|||||||
if (INVALID_HANDLE_VALUE != ChildHandles[1])
|
if (INVALID_HANDLE_VALUE != ChildHandles[1])
|
||||||
CloseHandle(ChildHandles[1]);
|
CloseHandle(ChildHandles[1]);
|
||||||
|
|
||||||
|
if (InitDoneAttrList)
|
||||||
|
DeleteProcThreadAttributeList(AttrList);
|
||||||
MemFree(AttrList);
|
MemFree(AttrList);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
@ -888,13 +903,16 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
SVC_INSTANCE **PSvcInstance)
|
SVC_INSTANCE **PSvcInstance)
|
||||||
{
|
{
|
||||||
SVC_INSTANCE *SvcInstance = 0;
|
SVC_INSTANCE *SvcInstance = 0;
|
||||||
PWSTR ClientUserName = 0;
|
PWSTR Argv[10];
|
||||||
|
PWSTR Varv[26];
|
||||||
|
SYSTEMTIME SystemTime;
|
||||||
|
PWSTR ClientUserName = 0, StderrFileName = 0;
|
||||||
DWORD ClientTokenInformation = -1;
|
DWORD ClientTokenInformation = -1;
|
||||||
|
SECURITY_ATTRIBUTES StderrSecurityAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, TRUE };
|
||||||
FSP_LAUNCH_REG_RECORD *Record = 0;
|
FSP_LAUNCH_REG_RECORD *Record = 0;
|
||||||
WCHAR CommandLine[512], Security[512];
|
WCHAR CurrentTime[32], CommandLine[512], Security[512];
|
||||||
DWORD Length, ClassNameSize, InstanceNameSize;
|
DWORD Length, ClassNameSize, InstanceNameSize;
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor = 0, NewSecurityDescriptor;
|
PSECURITY_DESCRIPTOR SecurityDescriptor = 0, NewSecurityDescriptor;
|
||||||
PWSTR Argv[10];
|
|
||||||
PROCESS_INFORMATION ProcessInfo;
|
PROCESS_INFORMATION ProcessInfo;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
@ -906,6 +924,8 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
Argv[0] = 0;
|
Argv[0] = 0;
|
||||||
Argc++;
|
Argc++;
|
||||||
|
|
||||||
|
memset(Varv, 0, sizeof Varv);
|
||||||
|
|
||||||
memset(&ProcessInfo, 0, sizeof ProcessInfo);
|
memset(&ProcessInfo, 0, sizeof ProcessInfo);
|
||||||
|
|
||||||
EnterCriticalSection(&SvcInstanceLock);
|
EnterCriticalSection(&SvcInstanceLock);
|
||||||
@ -916,9 +936,17 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetSystemTime(&SystemTime);
|
||||||
|
wsprintfW(CurrentTime, L"%04hu%02hu%02huT%02hu%02hu%02hu.%03huZ",
|
||||||
|
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay,
|
||||||
|
SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond,
|
||||||
|
SystemTime.wMilliseconds);
|
||||||
|
Varv[L'T' - L'A'] = CurrentTime;
|
||||||
|
|
||||||
Result = GetTokenUserName(ClientToken, &ClientUserName);
|
Result = GetTokenUserName(ClientToken, &ClientUserName);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
Varv[L'U' - L'A'] = ClientUserName;
|
||||||
|
|
||||||
Result = FspLaunchRegGetRecord(ClassName, 0, &Record);
|
Result = FspLaunchRegGetRecord(ClassName, 0, &Record);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
@ -1007,15 +1035,36 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
SvcInstance->SecurityDescriptor = SecurityDescriptor;
|
SvcInstance->SecurityDescriptor = SecurityDescriptor;
|
||||||
SvcInstance->StdioHandles[0] = INVALID_HANDLE_VALUE;
|
SvcInstance->StdioHandles[0] = INVALID_HANDLE_VALUE;
|
||||||
SvcInstance->StdioHandles[1] = INVALID_HANDLE_VALUE;
|
SvcInstance->StdioHandles[1] = INVALID_HANDLE_VALUE;
|
||||||
|
SvcInstance->StdioHandles[2] = INVALID_HANDLE_VALUE;
|
||||||
SvcInstance->Recovery = Record->Recovery;
|
SvcInstance->Recovery = Record->Recovery;
|
||||||
|
|
||||||
Result = SvcInstanceReplaceArguments(CommandLine,
|
Result = SvcInstanceReplaceArguments(CommandLine, Argc, Argv, Varv, TRUE,
|
||||||
Argc, Argv,
|
|
||||||
ClientUserName,
|
|
||||||
&SvcInstance->CommandLine);
|
&SvcInstance->CommandLine);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
if (0 != Record->Stderr)
|
||||||
|
{
|
||||||
|
Result = SvcInstanceReplaceArguments(Record->Stderr, Argc, Argv, Varv, FALSE,
|
||||||
|
&StderrFileName);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
SvcInstance->StdioHandles[2] = CreateFileW(
|
||||||
|
StderrFileName,
|
||||||
|
FILE_APPEND_DATA,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
&StderrSecurityAttributes,
|
||||||
|
OPEN_ALWAYS,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
0);
|
||||||
|
if (INVALID_HANDLE_VALUE == SvcInstance->StdioHandles[2])
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Result = SvcInstanceCreateProcess(
|
Result = SvcInstanceCreateProcess(
|
||||||
Record->RunAs,
|
Record->RunAs,
|
||||||
ClientToken,
|
ClientToken,
|
||||||
@ -1023,6 +1072,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
SvcInstance->CommandLine,
|
SvcInstance->CommandLine,
|
||||||
Record->WorkDirectory,
|
Record->WorkDirectory,
|
||||||
RedirectStdio ? SvcInstance->StdioHandles : 0,
|
RedirectStdio ? SvcInstance->StdioHandles : 0,
|
||||||
|
SvcInstance->StdioHandles[2],
|
||||||
&ProcessInfo);
|
&ProcessInfo);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
@ -1078,6 +1128,8 @@ exit:
|
|||||||
CloseHandle(SvcInstance->StdioHandles[0]);
|
CloseHandle(SvcInstance->StdioHandles[0]);
|
||||||
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
|
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
|
||||||
CloseHandle(SvcInstance->StdioHandles[1]);
|
CloseHandle(SvcInstance->StdioHandles[1]);
|
||||||
|
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[2])
|
||||||
|
CloseHandle(SvcInstance->StdioHandles[2]);
|
||||||
|
|
||||||
if (0 != SvcInstance->ProcessWait)
|
if (0 != SvcInstance->ProcessWait)
|
||||||
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
||||||
@ -1096,6 +1148,7 @@ exit:
|
|||||||
if (0 != Record)
|
if (0 != Record)
|
||||||
FspLaunchRegFreeRecord(Record);
|
FspLaunchRegFreeRecord(Record);
|
||||||
|
|
||||||
|
MemFree(StderrFileName);
|
||||||
MemFree(ClientUserName);
|
MemFree(ClientUserName);
|
||||||
|
|
||||||
LeaveCriticalSection(&SvcInstanceLock);
|
LeaveCriticalSection(&SvcInstanceLock);
|
||||||
@ -1133,6 +1186,8 @@ static VOID SvcInstanceRelease(SVC_INSTANCE *SvcInstance)
|
|||||||
CloseHandle(SvcInstance->StdioHandles[0]);
|
CloseHandle(SvcInstance->StdioHandles[0]);
|
||||||
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
|
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
|
||||||
CloseHandle(SvcInstance->StdioHandles[1]);
|
CloseHandle(SvcInstance->StdioHandles[1]);
|
||||||
|
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[2])
|
||||||
|
CloseHandle(SvcInstance->StdioHandles[2]);
|
||||||
|
|
||||||
if (0 != SvcInstance->ProcessWait)
|
if (0 != SvcInstance->ProcessWait)
|
||||||
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
||||||
@ -1256,6 +1311,11 @@ exit:
|
|||||||
CloseHandle(SvcInstance->StdioHandles[1]);
|
CloseHandle(SvcInstance->StdioHandles[1]);
|
||||||
SvcInstance->StdioHandles[1] = INVALID_HANDLE_VALUE;
|
SvcInstance->StdioHandles[1] = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[2])
|
||||||
|
{
|
||||||
|
CloseHandle(SvcInstance->StdioHandles[2]);
|
||||||
|
SvcInstance->StdioHandles[2] = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
if (NT_SUCCESS(Result))
|
if (NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user