dll: FspCallNamedPipeSecurely replaces CallNamedPipeW

This commit is contained in:
Bill Zissimopoulos 2016-05-18 10:05:33 -07:00
parent fea92c4ae0
commit f7adbaba92
5 changed files with 131 additions and 16 deletions

View File

@ -183,6 +183,11 @@
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\winfsp_dll.vcxproj">
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -1034,6 +1034,10 @@ FSP_API VOID FspEventLogV(ULONG Type, PWSTR Format, va_list ap);
FSP_API VOID FspDebugLog(const char *format, ...);
FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDescriptor);
FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime);
FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout,
PSID Sid);
#ifdef __cplusplus
}

View File

@ -17,11 +17,117 @@
#include <dll/library.h>
#include <launcher/launcher.h>
#include <aclapi.h>
#include <npapi.h>
#define FSP_NP_NAME LIBRARY_NAME ".Np"
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout,
PSID Sid)
{
NTSTATUS Result;
HANDLE Pipe = INVALID_HANDLE_VALUE;
DWORD PipeMode;
Pipe = CreateFileW(PipeName,
GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, 0);
if (INVALID_HANDLE_VALUE == Pipe)
{
if (ERROR_PIPE_BUSY != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
WaitNamedPipeW(PipeName, Timeout);
Pipe = CreateFileW(PipeName,
GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, 0);
if (INVALID_HANDLE_VALUE == Pipe)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
if (0 != Sid)
{
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSID OwnerSid, WellKnownSid = 0;
DWORD SidSize, LastError;
/* if it is a small number treat it like a well known SID */
if (1024 > (INT_PTR)Sid)
{
SidSize = SECURITY_MAX_SID_SIZE;
WellKnownSid = MemAlloc(SidSize);
if (0 == WellKnownSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto sid_exit;
}
if (!CreateWellKnownSid((INT_PTR)Sid, 0, WellKnownSid, &SidSize))
{
Result = FspNtStatusFromWin32(GetLastError());
goto sid_exit;
}
}
LastError = GetSecurityInfo(Pipe, SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION, &OwnerSid, 0, 0, 0, &SecurityDescriptor);
if (0 != LastError)
{
Result = FspNtStatusFromWin32(GetLastError());
goto sid_exit;
}
if (!EqualSid(OwnerSid, WellKnownSid ? WellKnownSid : Sid))
{
Result = STATUS_ACCESS_DENIED;
goto sid_exit;
}
Result = STATUS_SUCCESS;
sid_exit:
MemFree(WellKnownSid);
LocalFree(SecurityDescriptor);
if (!NT_SUCCESS(Result))
goto exit;
}
PipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
if (!SetNamedPipeHandleState(Pipe, &PipeMode, 0, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (!TransactNamedPipe(Pipe, InBuffer, InBufferSize, OutBuffer, OutBufferSize,
PBytesTransferred, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = STATUS_SUCCESS;
exit:
if (INVALID_HANDLE_VALUE != Pipe)
CloseHandle(Pipe);
return Result;
}
DWORD APIENTRY NPGetCaps(DWORD Index)
{
switch (Index)
@ -132,12 +238,13 @@ static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
{
DWORD NpResult;
DWORD LastError, BytesTransferred;
NTSTATUS Result;
DWORD BytesTransferred;
LastError = CallNamedPipeW(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT) ? 0 : GetLastError();
Result = FspCallNamedPipeSecurely(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, LAUNCHER_PIPE_OWNER);
if (0 != LastError)
if (!NT_SUCCESS(Result))
NpResult = WN_NO_NETWORK;
else if (sizeof(WCHAR) > BytesTransferred)
NpResult = WN_NO_NETWORK;

View File

@ -63,13 +63,15 @@ static void usage(void)
static int call_pipe_and_report(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
{
NTSTATUS Result;
DWORD LastError, BytesTransferred;
LastError = CallNamedPipeW(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT) ? 0 : GetLastError();
Result = FspCallNamedPipeSecurely(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, LAUNCHER_PIPE_OWNER);
LastError = FspWin32FromNtStatus(Result);
if (0 != LastError)
warn("KO CallNamedPipeW = %ld", LastError);
warn("KO CallNamedPipe = %ld", LastError);
else if (sizeof(WCHAR) > BytesTransferred)
warn("KO launcher: empty buffer");
else if (LauncherSuccess == PipeBuf[0])

View File

@ -29,16 +29,13 @@
#define LAUNCHER_PIPE_DEFAULT_TIMEOUT 3000
/*
* The launcher named pipe SDDL gives full access to LocalSystem and Administrators.
* It also gives GENERIC_READ and GENERIC_WRITE access to Everyone. This includes the
* FILE_CREATE_PIPE_INSTANCE right which should not normally be granted to any process
* 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).
* The launcher named pipe SDDL gives full access to LocalSystem and Administrators and
* GENERIC_READ and FILE_WRITE_DATA access to Everyone. We are careful not to give the
* FILE_CREATE_PIPE_INSTANCE right to Everyone to disallow the creation of additional
* pipe instances.
*/
#define LAUNCHER_PIPE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW;;;WD)"
#define LAUNCHER_PIPE_SDDL "O:SYG:SYD:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRDCCR;;;WD)"
#define LAUNCHER_PIPE_OWNER ((PSID)WinLocalSystemSid)
/*
* The default service instance SDDL gives full access to LocalSystem and Administrators.