431 lines
12 KiB
C
431 lines
12 KiB
C
/******************************************************************************
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
reclient.c
|
|
|
|
Abstract:
|
|
Implements access to the DW creation pipe.
|
|
|
|
Revision History:
|
|
created derekm 10/15/00
|
|
|
|
******************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include <pchrexec.h>
|
|
|
|
// **************************************************************************
|
|
BOOL MyCallNamedPipe(LPCWSTR wszPipe, LPVOID pvIn, DWORD cbIn,
|
|
LPVOID pvOut, DWORD cbOut, DWORD *pcbRead,
|
|
DWORD dwWaitPipe, DWORD dwWaitRead)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
HANDLE hPipe = INVALID_HANDLE_VALUE;
|
|
HANDLE hev = NULL;
|
|
DWORD dwStart = GetTickCount(), dwNow, dw;
|
|
BOOL fRet = FALSE;
|
|
|
|
if (wszPipe == NULL || pvIn == NULL || pvOut == NULL || pcbRead == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
goto done;
|
|
}
|
|
|
|
*pcbRead = 0;
|
|
|
|
for(;;)
|
|
{
|
|
hPipe = CreateFileW(wszPipe, GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
|
|
NULL);
|
|
if (hPipe != INVALID_HANDLE_VALUE)
|
|
break;
|
|
|
|
fRet = WaitNamedPipeW(wszPipe, dwWaitPipe);
|
|
if (fRet == FALSE)
|
|
goto done;
|
|
|
|
dwNow = GetTickCount();
|
|
if (dwNow < dwStart)
|
|
dw = ((DWORD)-1 - dwStart) + dwNow;
|
|
else
|
|
dw = dwNow - dwStart;
|
|
if (dw >= dwWaitPipe)
|
|
dwWaitPipe = 0;
|
|
else
|
|
dwWaitPipe -= dw;
|
|
}
|
|
|
|
|
|
__try
|
|
{
|
|
OVERLAPPED ol;
|
|
DWORD dwMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
|
|
DWORD cbRead = 0;
|
|
|
|
__try
|
|
{
|
|
// Default open is readmode byte stream- change to message mode.
|
|
fRet = SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL);
|
|
if (fRet == FALSE)
|
|
__leave;
|
|
|
|
// we need an event for the overlapped structure
|
|
hev = CreateEventW(NULL, TRUE, FALSE, NULL);
|
|
if (hev == NULL)
|
|
{
|
|
fRet = FALSE;
|
|
__leave;
|
|
}
|
|
|
|
// populate the overlapped stuff
|
|
ZeroMemory(&ol, sizeof(ol));
|
|
ol.hEvent = hev;
|
|
|
|
if (GetSystemMetrics(SM_SHUTTINGDOWN))
|
|
{
|
|
SetLastError(WAIT_TIMEOUT);
|
|
__leave;
|
|
}
|
|
|
|
fRet = TransactNamedPipe(hPipe, pvIn, cbIn, pvOut, cbOut, &cbRead,
|
|
&ol);
|
|
if (GetLastError() != ERROR_IO_PENDING)
|
|
{
|
|
if (fRet)
|
|
SetEvent(hev);
|
|
else
|
|
__leave;
|
|
}
|
|
|
|
dw = WaitForSingleObject(hev, dwWaitRead);
|
|
if (dw != WAIT_OBJECT_0)
|
|
{
|
|
if (dw == WAIT_TIMEOUT)
|
|
SetLastError(WAIT_TIMEOUT);
|
|
__leave;
|
|
}
|
|
|
|
fRet = GetOverlappedResult(hPipe, &ol, &cbRead, FALSE);
|
|
if (fRet == FALSE)
|
|
__leave;
|
|
|
|
*pcbRead = cbRead;
|
|
|
|
hr = NOERROR;
|
|
}
|
|
|
|
__finally
|
|
{
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
done:
|
|
dw = GetLastError();
|
|
|
|
if (hPipe != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hPipe);
|
|
if (hev != NULL)
|
|
CloseHandle(hev);
|
|
|
|
SetLastError(dw);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
LPWSTR MarshallString(LPWSTR wszSrc, PBYTE pBase, ULONG cbMaxBuf,
|
|
PBYTE *ppToWrite, DWORD *pcbWritten)
|
|
{
|
|
DWORD cb;
|
|
PBYTE pwszNormalized;
|
|
|
|
cb = (wcslen(wszSrc) + 1) * sizeof(WCHAR);
|
|
|
|
if ((*pcbWritten + cb) > cbMaxBuf)
|
|
return NULL;
|
|
|
|
RtlMoveMemory(*ppToWrite, wszSrc, cb);
|
|
|
|
// the normalized ptr is the current count
|
|
pwszNormalized = (PBYTE)(*ppToWrite - pBase);
|
|
|
|
// cb is always a mutliple of sizeof(WHCAR) so the pointer addition below
|
|
// always produces a result that is 2byte aligned (assuming the input was
|
|
// 2byte aligned of course)
|
|
*ppToWrite += cb;
|
|
*pcbWritten += cb;
|
|
|
|
return (LPWSTR)pwszNormalized;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
BOOL StartHangReport(ULONG ulSessionId, LPWSTR wszEventName, DWORD dwpidHung,
|
|
DWORD dwtidHung, BOOL f64Bit, HANDLE *phProcDumprep)
|
|
{
|
|
SPCHExecServHangRequest *pesreq;
|
|
SPCHExecServHangReply esrep;
|
|
DWORD cbRead, cbReq;
|
|
WCHAR wszPipeName[MAX_PATH];
|
|
BYTE Buf[ERRORREP_PIPE_BUF_SIZE];
|
|
BYTE *pBuf;
|
|
BOOL fRet = FALSE;
|
|
|
|
// validate params
|
|
if (wszEventName == NULL || phProcDumprep == NULL || dwpidHung == 0 ||
|
|
dwtidHung == 0)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
goto done;
|
|
}
|
|
|
|
*phProcDumprep = NULL;
|
|
|
|
wcscpy(wszPipeName, ERRORREP_HANG_PIPENAME);
|
|
|
|
// setup the marshalling- make sure that pBuf is aligned on a 2byte
|
|
// boundary beacause we'll be writing WCHAR buffers to it.
|
|
ZeroMemory(Buf, sizeof(Buf));
|
|
pesreq = (SPCHExecServHangRequest *)Buf;
|
|
cbReq = sizeof(SPCHExecServHangRequest) +
|
|
(sizeof(WCHAR) -
|
|
(sizeof(SPCHExecServHangRequest) % sizeof(WCHAR)));
|
|
pBuf = Buf + cbReq;
|
|
|
|
// set the basic parameters
|
|
pesreq->cbESR = sizeof(SPCHExecServHangRequest);
|
|
pesreq->pidReqProcess = GetCurrentProcessId();
|
|
pesreq->ulSessionId = ulSessionId;
|
|
pesreq->dwpidHung = dwpidHung;
|
|
pesreq->dwtidHung = dwtidHung;
|
|
pesreq->fIs64bit = f64Bit;
|
|
|
|
|
|
// marshall all the strings we send across the wire.
|
|
|
|
// CommandLine
|
|
if (wszEventName != NULL)
|
|
{
|
|
pesreq->wszEventName = (UINT64)MarshallString(wszEventName, Buf,
|
|
sizeof(Buf), &pBuf,
|
|
&cbReq);
|
|
if (pesreq->wszEventName == 0)
|
|
goto done;
|
|
}
|
|
|
|
// set the total size of the message
|
|
pesreq->cbTotal = cbReq;
|
|
|
|
if (GetSystemMetrics(SM_SHUTTINGDOWN))
|
|
{
|
|
SetLastError(WAIT_TIMEOUT);
|
|
goto done;
|
|
}
|
|
|
|
// Send the buffer out to the server- wait at most 2m for this to
|
|
// succeed. If it times out, bail.
|
|
fRet = MyCallNamedPipe(wszPipeName, Buf, cbReq, &esrep, sizeof(esrep),
|
|
&cbRead, 120000, 120000);
|
|
if (fRet == FALSE)
|
|
goto done;
|
|
|
|
// Check the result
|
|
fRet = (esrep.ess == essOk);
|
|
if (fRet == FALSE)
|
|
{
|
|
SetLastError(esrep.dwErr);
|
|
goto done;
|
|
}
|
|
|
|
*phProcDumprep = esrep.hProcess;
|
|
|
|
done:
|
|
return fRet;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
NTSTATUS AllocDefSD(SECURITY_DESCRIPTOR *psd, DWORD dwOALS, DWORD dwWA)
|
|
{
|
|
SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY;
|
|
TOKEN_USER *ptu = NULL;
|
|
NTSTATUS Status;
|
|
HANDLE hToken = NULL;
|
|
DWORD cb, cbGot;
|
|
PACL pacl = NULL;
|
|
PSID psidOwner = NULL;
|
|
PSID psidLS = NULL;
|
|
PSID psidWorld = NULL;
|
|
PSID psidAnon = NULL;
|
|
|
|
if (psd == NULL)
|
|
{
|
|
SetLastError(STATUS_INVALID_PARAMETER_1);
|
|
goto done;
|
|
}
|
|
|
|
Status = RtlCreateSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
// get the SID for the creator / owner
|
|
Status = NtOpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken);
|
|
if (NT_SUCCESS(Status) == FALSE && Status == STATUS_NO_TOKEN)
|
|
Status = NtOpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
Status = NtQueryInformationToken(hToken, TokenUser, NULL, 0, &cb);
|
|
if (NT_SUCCESS(Status) == FALSE && Status != STATUS_BUFFER_TOO_SMALL)
|
|
goto done;
|
|
|
|
__try { ptu = (TOKEN_USER *)_alloca(cb); }
|
|
__except(EXCEPTION_EXECUTE_HANDLER) { ptu = NULL; }
|
|
if (ptu == NULL)
|
|
{
|
|
Status = STATUS_SECTION_NOT_EXTENDED;
|
|
goto done;
|
|
}
|
|
|
|
Status = NtQueryInformationToken(hToken, TokenUser, (LPVOID)ptu, cb, &cbGot);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
// make a copy of the owner SID so we can use it in the owner & group field
|
|
cb = RtlLengthSid(ptu->User.Sid);
|
|
psidOwner = (PSID)LocalAlloc(LMEM_FIXED, cb);
|
|
if (psidOwner == NULL)
|
|
{
|
|
Status = STATUS_SECTION_NOT_EXTENDED;
|
|
goto done;
|
|
}
|
|
|
|
Status = RtlCopySid(cb, psidOwner, ptu->User.Sid);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
// get the SID for local system acct
|
|
Status = RtlAllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID,
|
|
0, 0, 0, 0, 0, 0, 0, &psidLS);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
cb = sizeof(ACL) + RtlLengthSid(psidLS) + RtlLengthSid(psidOwner) +
|
|
2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD));
|
|
|
|
if (dwWA != 0)
|
|
{
|
|
// get the SID for the world (everyone)
|
|
Status = RtlAllocateAndInitializeSid(&siaNT, 1,
|
|
SECURITY_ANONYMOUS_LOGON_RID,
|
|
0, 0, 0, 0, 0, 0, 0, &psidWorld);
|
|
|
|
|
|
// get the SID for the anonymous users acct
|
|
Status = RtlAllocateAndInitializeSid(&siaWorld, 1, SECURITY_WORLD_RID,
|
|
0, 0, 0, 0, 0, 0, 0, &psidAnon);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
cb += RtlLengthSid(psidWorld) + RtlLengthSid(psidAnon) +
|
|
2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD));
|
|
}
|
|
|
|
// make the DACL
|
|
pacl = (PACL)LocalAlloc(LMEM_FIXED, cb);
|
|
if (pacl == NULL)
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
goto done;
|
|
}
|
|
|
|
Status = RtlCreateAcl(pacl, cb, ACL_REVISION);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
Status = RtlAddAccessAllowedAce(pacl, ACL_REVISION, dwOALS, psidOwner);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
Status = RtlAddAccessAllowedAce(pacl, ACL_REVISION, dwOALS, psidLS);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
if (dwWA != 0)
|
|
{
|
|
Status = RtlAddAccessAllowedAce(pacl, ACL_REVISION, dwWA, psidWorld);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
Status = RtlAddAccessAllowedAce(pacl, ACL_REVISION, dwWA, psidAnon);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
}
|
|
|
|
// set the SD owner
|
|
Status = RtlSetOwnerSecurityDescriptor(psd, psidOwner, TRUE);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
// set the SD group
|
|
Status = RtlSetGroupSecurityDescriptor(psd, psidOwner, FALSE);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
// set the SD dacl
|
|
Status = RtlSetDaclSecurityDescriptor(psd, TRUE, pacl, FALSE);
|
|
if (NT_SUCCESS(Status) == FALSE)
|
|
goto done;
|
|
|
|
psidOwner = NULL;
|
|
pacl = NULL;
|
|
|
|
done:
|
|
|
|
if (hToken != NULL)
|
|
CloseHandle(hToken);
|
|
|
|
if (psidLS != NULL)
|
|
RtlFreeSid(psidLS);
|
|
if (psidWorld != NULL)
|
|
RtlFreeSid(psidWorld);
|
|
if (psidAnon != NULL)
|
|
RtlFreeSid(psidAnon);
|
|
if (psidOwner != NULL)
|
|
LocalFree(psidOwner);
|
|
if (pacl != NULL)
|
|
LocalFree(pacl);
|
|
|
|
return Status;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void FreeDefSD(SECURITY_DESCRIPTOR *psd)
|
|
{
|
|
BOOLEAN f1, f2;
|
|
PSID psid = NULL;
|
|
PACL pacl = NULL;
|
|
|
|
if (psd == NULL)
|
|
return;
|
|
|
|
if (NT_SUCCESS(RtlGetOwnerSecurityDescriptor(psd, &psid, &f1)))
|
|
{
|
|
if (psid != NULL)
|
|
LocalFree(psid);
|
|
}
|
|
|
|
if (NT_SUCCESS(RtlGetDaclSecurityDescriptor(psd, &f1, &pacl, &f2)))
|
|
{
|
|
if (pacl != NULL)
|
|
LocalFree(pacl);
|
|
}
|
|
}
|