You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1042 lines
30 KiB
1042 lines
30 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
All rights reserved
|
|
|
|
Module Name:
|
|
|
|
utils.cxx
|
|
|
|
Abstract:
|
|
|
|
utils
|
|
|
|
Author:
|
|
|
|
Larry Zhu (LZhu) December 1, 2001 Created
|
|
|
|
Environment:
|
|
|
|
User Mode -Win32
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "utils.hxx"
|
|
|
|
#include <Sddl.h>
|
|
|
|
#define MAXDWORD 0xffffffff
|
|
|
|
NTSTATUS
|
|
CreateUnicodeStringFromAsciiz(
|
|
IN PCSZ pszSourceString,
|
|
OUT UNICODE_STRING* pDestinationString
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
|
|
ANSI_STRING AnsiString;
|
|
|
|
RtlInitAnsiString( &AnsiString, pszSourceString );
|
|
|
|
Status DBGCHK = RtlAnsiStringToUnicodeString(
|
|
pDestinationString,
|
|
&AnsiString,
|
|
TRUE
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
PackStringAsString32(
|
|
IN VOID* pvBufferBase,
|
|
IN OUT STRING* pString
|
|
)
|
|
{
|
|
pString->Buffer = (CHAR*) (pString->Buffer - (CHAR*) pvBufferBase);
|
|
}
|
|
|
|
NTSTATUS
|
|
CreateString32FromAsciiz(
|
|
IN VOID* pvBufferBase,
|
|
IN PCSZ pszSourceString,
|
|
OUT UNICODE_STRING* pDestinationString
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
|
|
Status DBGCHK = CreateUnicodeStringFromAsciiz(pszSourceString, pDestinationString);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
PackStringAsString32(pvBufferBase, (STRING*) pDestinationString);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
RelocatePackString(
|
|
IN OUT STRING* pString,
|
|
IN OUT CHAR** ppWhere
|
|
)
|
|
{
|
|
RtlCopyMemory(*ppWhere, pString->Buffer, pString->Length);
|
|
pString->Buffer = *ppWhere;
|
|
*ppWhere += pString->Length;
|
|
}
|
|
|
|
VOID
|
|
RelocatePackUnicodeString(
|
|
IN UNICODE_STRING* pString,
|
|
IN OUT CHAR** ppWhere
|
|
)
|
|
{
|
|
RelocatePackString((STRING*) pString, ppWhere);
|
|
}
|
|
|
|
VOID
|
|
PackUnicodeStringAsUnicodeStringZ(
|
|
IN UNICODE_STRING* pString,
|
|
IN OUT WCHAR** ppWhere,
|
|
OUT UNICODE_STRING* pDestString
|
|
)
|
|
{
|
|
RtlCopyMemory(*ppWhere, pString->Buffer, pString->Length);
|
|
pDestString->Buffer = *ppWhere;
|
|
|
|
pDestString->Length = pString->Length;
|
|
pDestString->MaximumLength = pString->Length + sizeof(WCHAR);
|
|
|
|
*ppWhere += pDestString->MaximumLength / sizeof(WCHAR);
|
|
|
|
//
|
|
// add unicode NULL
|
|
//
|
|
|
|
pDestString->Buffer[(pDestString->MaximumLength / sizeof(WCHAR)) - 1] = UNICODE_NULL;
|
|
}
|
|
|
|
VOID
|
|
PackString(
|
|
IN STRING* pString,
|
|
IN OUT CHAR** ppWhere,
|
|
OUT STRING* pDestString
|
|
)
|
|
{
|
|
RtlCopyMemory(*ppWhere, pString->Buffer, pString->Length);
|
|
pDestString->Buffer = *ppWhere;
|
|
*ppWhere += pString->Length;
|
|
|
|
pDestString->Length = pString->Length;
|
|
pDestString->MaximumLength = pString->Length;
|
|
}
|
|
|
|
VOID
|
|
DebugPrintSysTimeAsLocalTime(
|
|
IN ULONG ulLevel,
|
|
IN PCSTR pszBanner,
|
|
IN LARGE_INTEGER* pSysTime
|
|
)
|
|
{
|
|
TNtStatus NtStatus = STATUS_UNSUCCESSFUL;
|
|
TIME_FIELDS TimeFields = {0};
|
|
LARGE_INTEGER LocalTime = {0};
|
|
|
|
NtStatus DBGCHK = RtlSystemTimeToLocalTime(pSysTime, &LocalTime);
|
|
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
RtlTimeToTimeFields(&LocalTime, &TimeFields);
|
|
DebugPrintf(ulLevel, "%s LocalTime(%ld/%ld/%ld %ld:%2.2ld:%2.2ld) SystemTime(H%8.8lx L%8.8lx)\n",
|
|
pszBanner,
|
|
TimeFields.Month,
|
|
TimeFields.Day,
|
|
TimeFields.Year,
|
|
TimeFields.Hour,
|
|
TimeFields.Minute,
|
|
TimeFields.Second,
|
|
pSysTime->HighPart,
|
|
pSysTime->LowPart);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DebugPrintLocalTime(
|
|
IN ULONG ulLevel,
|
|
IN PCSTR pszBanner,
|
|
IN LARGE_INTEGER* pLocalTime
|
|
)
|
|
{
|
|
TIME_FIELDS TimeFields = {0};
|
|
|
|
RtlTimeToTimeFields(pLocalTime, &TimeFields);
|
|
DebugPrintf(ulLevel, "%s LocalTime(%ld/%ld/%ld %ld:%2.2ld:%2.2ld) H%8.8lx L%8.8lx\n",
|
|
pszBanner,
|
|
TimeFields.Month,
|
|
TimeFields.Day,
|
|
TimeFields.Year,
|
|
TimeFields.Hour,
|
|
TimeFields.Minute,
|
|
TimeFields.Second,
|
|
pLocalTime->HighPart,
|
|
pLocalTime->LowPart);
|
|
}
|
|
|
|
#define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED)
|
|
|
|
#define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN | STANDARD_RIGHTS_REQUIRED)
|
|
|
|
#define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
|
|
|
|
HRESULT
|
|
StartInteractiveClientProcessAsUser(
|
|
IN HANDLE hToken,
|
|
IN PTSTR pszCommandLine // command line to execute
|
|
)
|
|
{
|
|
THResult hRetval = E_FAIL;
|
|
|
|
HANDLE hDup = NULL;
|
|
HDESK hdesk = NULL;
|
|
HWINSTA hwinsta = NULL;
|
|
HWINSTA hwinstaSave = NULL;
|
|
PROCESS_INFORMATION pi = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0};
|
|
PSID pSid = NULL;
|
|
STARTUPINFO si = {0};
|
|
HANDLE hSystemToken = NULL;
|
|
CHAR TokenUserInfoBuffer[MAX_PATH + sizeof(TOKEN_USER)] = {0}; // MAX_SID_SIZE is 256
|
|
TOKEN_USER* pTokenUserInfo = (TOKEN_USER*) TokenUserInfoBuffer;
|
|
ULONG cbReturn = 0;
|
|
|
|
// Save a handle to the caller's current window station.
|
|
|
|
hwinstaSave = GetProcessWindowStation();
|
|
|
|
hRetval DBGCHK = hwinstaSave ? S_OK : GetLastErrorAsHResult();
|
|
|
|
// Get the SID for the client's logon session.
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = GetLogonSIDOrUserSid(hToken, &pSid) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
// Get a handle to the interactive window station.
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hwinsta = OpenWindowStation(
|
|
TEXT("winsta0"), // the interactive window station
|
|
FALSE, // handle is not inheritable
|
|
MAXIMUM_ALLOWED // rights to read/write the DACL
|
|
);
|
|
hRetval DBGCHK = hwinsta ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
// Allow logon SID full access to interactive window station.
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = AddAceToWindowStation(hwinsta, pSid) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
// To get the correct default desktop, set the caller's
|
|
// window station to the interactive window station.
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = SetProcessWindowStation(hwinsta) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
// Get a handle to the interactive desktop.
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
TImpersonation imper(NULL);
|
|
|
|
hRetval DBGCHK = imper.Validate();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hdesk = OpenDesktop(
|
|
TEXT("default"), // the interactive window station
|
|
0, // no interaction with other desktop processes
|
|
FALSE, // handle is not inheritable
|
|
MAXIMUM_ALLOWED
|
|
);
|
|
hRetval DBGCHK = hdesk ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
// Allow logon SID full access to interactive desktop.
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = AddAceToDesktop(hdesk, pSid) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
}
|
|
|
|
//
|
|
// get the necessary privileges enabled
|
|
//
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = GetSystemToken(&hSystemToken);
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
TImpersonation imper(hSystemToken);
|
|
|
|
hRetval DBGCHK = imper.Validate();
|
|
|
|
// Allow logon SID full access to interactive desktop.
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = SetThreadDesktop(hdesk) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = GetTokenInformation(
|
|
hToken,
|
|
TokenUser,
|
|
TokenUserInfoBuffer,
|
|
sizeof(TokenUserInfoBuffer),
|
|
&cbReturn
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
// Initialize the STARTUPINFO structure.
|
|
// Specify that the process runs in the interactive desktop.
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
si.cb = sizeof(STARTUPINFO);
|
|
si.lpDesktop = TEXT("winsta0\\default");
|
|
|
|
hRetval DBGCHK = ConvertSidToStringSid(pTokenUserInfo->User.Sid, &si.lpTitle) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
// Launch the process in the client's logon session.
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
DBGCFG1(hRetval, HRESULT_FROM_WIN32(ERROR_BAD_TOKEN_TYPE));
|
|
|
|
hRetval DBGCHK = CreateProcessAsUser(
|
|
hToken, // client's access token
|
|
NULL, // file to execute
|
|
pszCommandLine, // command line
|
|
NULL, // pointer to process SECURITY_ATTRIBUTES
|
|
NULL, // pointer to thread SECURITY_ATTRIBUTES
|
|
FALSE, // handles are not inheritable
|
|
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // creation flags
|
|
NULL, // pointer to new environment block
|
|
NULL, // name of current directory
|
|
&si, // pointer to STARTUPINFO structure
|
|
&pi // receives information about new process
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (FAILED(hRetval) && (ERROR_BAD_TOKEN_TYPE == HRESULT_CODE(hRetval)))
|
|
{
|
|
DebugPrintf(SSPI_WARN, "CreateProcessAsUser failed with ERROR_BAD_TOKEN_TYPE\n");
|
|
|
|
hRetval DBGCHK = DuplicateTokenEx(
|
|
hToken,
|
|
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenPrimary,
|
|
&hDup
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = CreateProcessAsUser(
|
|
hDup, // client's access token
|
|
NULL, // file to execute
|
|
pszCommandLine, // command line
|
|
NULL, // pointer to process SECURITY_ATTRIBUTES
|
|
NULL, // pointer to thread SECURITY_ATTRIBUTES
|
|
FALSE, // handles are not inheritable
|
|
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // creation flags
|
|
NULL, // pointer to new environment block
|
|
NULL, // name of current directory
|
|
&si, // pointer to STARTUPINFO structure
|
|
&pi // receives information about new process
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
SspiPrint(SSPI_LOG, TEXT("StartInteractiveClientProcessAsUser succeeded: process id %d(%#x), user is %s, pszCommandLine \"%s\"\n"), pi.dwProcessId, pi.dwProcessId, si.lpTitle, pszCommandLine);
|
|
}
|
|
|
|
if (si.lpTitle)
|
|
{
|
|
LocalFree(si.lpTitle);
|
|
}
|
|
}
|
|
|
|
THResult hr;
|
|
|
|
// Restore the caller's window station.
|
|
|
|
if (hwinstaSave)
|
|
{
|
|
hr DBGCHK = SetProcessWindowStation(hwinstaSave) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
hr DBGCHK = CloseWindowStation(hwinstaSave) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (hDup)
|
|
{
|
|
hr DBGCHK = CloseHandle(hDup) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (hSystemToken)
|
|
{
|
|
hr DBGCHK = CloseHandle(hSystemToken) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (pi.hProcess != INVALID_HANDLE_VALUE)
|
|
{
|
|
// WaitForSingleObject(pi.hProcess, INFINITE);
|
|
hr DBGCHK = CloseHandle(pi.hProcess) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (pi.hThread != INVALID_HANDLE_VALUE)
|
|
{
|
|
hr DBGCHK = CloseHandle(pi.hThread) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
// Close the handles to the interactive window station and desktop.
|
|
|
|
if (hwinsta)
|
|
{
|
|
hr DBGCHK = CloseWindowStation(hwinsta) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (hdesk)
|
|
{
|
|
DBGCFG1(hr, HRESULT_FROM_WIN32(ERROR_BUSY));
|
|
|
|
hr DBGCHK = CloseDesktop(hdesk) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
// Free the buffer for the logon SID.
|
|
|
|
if (pSid)
|
|
{
|
|
FreeLogonSID(&pSid);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
BOOL AddAceToWindowStation(IN HWINSTA hwinsta, IN PSID psid)
|
|
{
|
|
ACCESS_ALLOWED_ACE *pace;
|
|
ACL_SIZE_INFORMATION aclSizeInfo;
|
|
BOOL bDaclExist;
|
|
BOOL bDaclPresent;
|
|
BOOL bSuccess = FALSE;
|
|
DWORD dwNewAclSize;
|
|
DWORD dwSidSize = 0;
|
|
DWORD dwSdSizeNeeded;
|
|
PACL pacl;
|
|
PACL pNewAcl;
|
|
PSECURITY_DESCRIPTOR psd = NULL;
|
|
PSECURITY_DESCRIPTOR psdNew = NULL;
|
|
PVOID pTempAce;
|
|
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
|
|
unsigned int i;
|
|
|
|
__try
|
|
{
|
|
// Obtain the DACL for the window station.
|
|
|
|
if (!GetUserObjectSecurity(
|
|
hwinsta,
|
|
&si,
|
|
psd,
|
|
dwSidSize,
|
|
&dwSdSizeNeeded))
|
|
{
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwSdSizeNeeded);
|
|
|
|
if (psd == NULL)
|
|
__leave;
|
|
|
|
psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwSdSizeNeeded);
|
|
|
|
if (psdNew == NULL)
|
|
__leave;
|
|
|
|
dwSidSize = dwSdSizeNeeded;
|
|
|
|
if (!GetUserObjectSecurity(
|
|
hwinsta,
|
|
&si,
|
|
psd,
|
|
dwSidSize,
|
|
&dwSdSizeNeeded))
|
|
__leave;
|
|
}
|
|
else
|
|
__leave;
|
|
}
|
|
|
|
// Create a new DACL.
|
|
|
|
if (!InitializeSecurityDescriptor(
|
|
psdNew,
|
|
SECURITY_DESCRIPTOR_REVISION))
|
|
__leave;
|
|
|
|
// Get the DACL from the security descriptor.
|
|
|
|
if (!GetSecurityDescriptorDacl(
|
|
psd,
|
|
&bDaclPresent,
|
|
&pacl,
|
|
&bDaclExist))
|
|
__leave;
|
|
|
|
// Initialize the ACL.
|
|
|
|
ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
|
|
aclSizeInfo.AclBytesInUse = sizeof(ACL);
|
|
|
|
// Call only if the DACL is not NULL.
|
|
|
|
if (pacl != NULL)
|
|
{
|
|
// get the file ACL size info
|
|
if (!GetAclInformation(
|
|
pacl,
|
|
(PVOID)&aclSizeInfo,
|
|
sizeof(ACL_SIZE_INFORMATION),
|
|
AclSizeInformation))
|
|
__leave;
|
|
}
|
|
|
|
// Compute the size of the new ACL.
|
|
|
|
dwNewAclSize = aclSizeInfo.AclBytesInUse + (2 * sizeof(ACCESS_ALLOWED_ACE))
|
|
+ (2 * GetLengthSid(psid)) - (2 * sizeof(DWORD));
|
|
|
|
// Allocate memory for the new ACL.
|
|
|
|
pNewAcl = (PACL)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwNewAclSize);
|
|
|
|
if (pNewAcl == NULL)
|
|
__leave;
|
|
|
|
// Initialize the new DACL.
|
|
|
|
if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
|
|
__leave;
|
|
|
|
// If DACL is present, copy it to a new DACL.
|
|
|
|
if (bDaclPresent)
|
|
{
|
|
// Copy the ACEs to the new ACL.
|
|
if (aclSizeInfo.AceCount)
|
|
{
|
|
for (i=0; i < aclSizeInfo.AceCount; i++)
|
|
{
|
|
// Get an ACE.
|
|
if (!GetAce(pacl, i, &pTempAce))
|
|
__leave;
|
|
|
|
// Add the ACE to the new ACL.
|
|
if (!AddAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD,
|
|
pTempAce,
|
|
((PACE_HEADER)pTempAce)->AceSize))
|
|
__leave;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add the first ACE to the window station.
|
|
|
|
pace = (ACCESS_ALLOWED_ACE *)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) -
|
|
sizeof(DWORD));
|
|
|
|
if (pace == NULL)
|
|
__leave;
|
|
|
|
pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
|
|
pace->Header.AceFlags = CONTAINER_INHERIT_ACE |
|
|
INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
|
|
pace->Header.AceSize = (USHORT) (sizeof(ACCESS_ALLOWED_ACE) +
|
|
GetLengthSid(psid) - sizeof(DWORD));
|
|
pace->Mask = GENERIC_ACCESS;
|
|
|
|
if (!CopySid(GetLengthSid(psid), &pace->SidStart, psid))
|
|
__leave;
|
|
|
|
if (!AddAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD,
|
|
(PVOID)pace,
|
|
pace->Header.AceSize))
|
|
__leave;
|
|
|
|
// Add the second ACE to the window station.
|
|
|
|
pace->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE;
|
|
pace->Mask = WINSTA_ALL;
|
|
|
|
if (!AddAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD,
|
|
(PVOID)pace,
|
|
pace->Header.AceSize))
|
|
__leave;
|
|
|
|
// Set a new DACL for the security descriptor.
|
|
|
|
if (!SetSecurityDescriptorDacl(
|
|
psdNew,
|
|
TRUE,
|
|
pNewAcl,
|
|
FALSE))
|
|
__leave;
|
|
|
|
// Set the new security descriptor for the window station.
|
|
|
|
if (!SetUserObjectSecurity(hwinsta, &si, psdNew))
|
|
__leave;
|
|
|
|
// Indicate success.
|
|
|
|
bSuccess = TRUE;
|
|
}
|
|
__finally
|
|
{
|
|
// Free the allocated buffers.
|
|
|
|
if (pace != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)pace);
|
|
|
|
if (pNewAcl != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)pNewAcl);
|
|
|
|
if (psd != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)psd);
|
|
|
|
if (psdNew != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)psdNew);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL AddAceToDesktop(IN HDESK hdesk, IN PSID psid)
|
|
{
|
|
ACL_SIZE_INFORMATION aclSizeInfo;
|
|
BOOL bDaclExist;
|
|
BOOL bDaclPresent;
|
|
BOOL bSuccess = FALSE;
|
|
DWORD dwNewAclSize;
|
|
DWORD dwSidSize = 0;
|
|
DWORD dwSdSizeNeeded;
|
|
PACL pacl;
|
|
PACL pNewAcl;
|
|
PSECURITY_DESCRIPTOR psd = NULL;
|
|
PSECURITY_DESCRIPTOR psdNew = NULL;
|
|
PVOID pTempAce;
|
|
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
|
|
unsigned int i;
|
|
|
|
__try
|
|
{
|
|
// Obtain the security descriptor for the desktop object.
|
|
|
|
if (!GetUserObjectSecurity(
|
|
hdesk,
|
|
&si,
|
|
psd,
|
|
dwSidSize,
|
|
&dwSdSizeNeeded))
|
|
{
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwSdSizeNeeded );
|
|
|
|
if (psd == NULL)
|
|
__leave;
|
|
|
|
psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwSdSizeNeeded);
|
|
|
|
if (psdNew == NULL)
|
|
__leave;
|
|
|
|
dwSidSize = dwSdSizeNeeded;
|
|
|
|
if (!GetUserObjectSecurity(
|
|
hdesk,
|
|
&si,
|
|
psd,
|
|
dwSidSize,
|
|
&dwSdSizeNeeded))
|
|
__leave;
|
|
}
|
|
else
|
|
__leave;
|
|
}
|
|
|
|
// Create a new security descriptor.
|
|
|
|
if (!InitializeSecurityDescriptor(
|
|
psdNew,
|
|
SECURITY_DESCRIPTOR_REVISION))
|
|
__leave;
|
|
|
|
// Obtain the DACL from the security descriptor.
|
|
|
|
if (!GetSecurityDescriptorDacl(
|
|
psd,
|
|
&bDaclPresent,
|
|
&pacl,
|
|
&bDaclExist))
|
|
__leave;
|
|
|
|
// Initialize.
|
|
|
|
ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
|
|
aclSizeInfo.AclBytesInUse = sizeof(ACL);
|
|
|
|
// Call only if NULL DACL.
|
|
|
|
if (pacl != NULL)
|
|
{
|
|
// Determine the size of the ACL information.
|
|
|
|
if (!GetAclInformation(
|
|
pacl,
|
|
(PVOID)&aclSizeInfo,
|
|
sizeof(ACL_SIZE_INFORMATION),
|
|
AclSizeInformation))
|
|
__leave;
|
|
}
|
|
|
|
// Compute the size of the new ACL.
|
|
|
|
dwNewAclSize = aclSizeInfo.AclBytesInUse +
|
|
sizeof(ACCESS_ALLOWED_ACE) +
|
|
GetLengthSid(psid) - sizeof(DWORD);
|
|
|
|
// Allocate buffer for the new ACL.
|
|
|
|
pNewAcl = (PACL)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwNewAclSize);
|
|
|
|
if (pNewAcl == NULL)
|
|
__leave;
|
|
|
|
// Initialize the new ACL.
|
|
|
|
if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
|
|
__leave;
|
|
|
|
// If DACL is present, copy it to a new DACL.
|
|
|
|
if (bDaclPresent)
|
|
{
|
|
// Copy the ACEs to the new ACL.
|
|
if (aclSizeInfo.AceCount)
|
|
{
|
|
for (i=0; i < aclSizeInfo.AceCount; i++)
|
|
{
|
|
// Get an ACE.
|
|
if (!GetAce(pacl, i, &pTempAce))
|
|
__leave;
|
|
|
|
// Add the ACE to the new ACL.
|
|
if (!AddAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD,
|
|
pTempAce,
|
|
((PACE_HEADER)pTempAce)->AceSize))
|
|
__leave;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add ACE to the DACL.
|
|
|
|
if (!AddAccessAllowedAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
DESKTOP_ALL,
|
|
psid))
|
|
__leave;
|
|
|
|
// Set new DACL to the new security descriptor.
|
|
|
|
if (!SetSecurityDescriptorDacl(
|
|
psdNew,
|
|
TRUE,
|
|
pNewAcl,
|
|
FALSE))
|
|
__leave;
|
|
|
|
// Set the new security descriptor for the desktop object.
|
|
|
|
if (!SetUserObjectSecurity(hdesk, &si, psdNew))
|
|
__leave;
|
|
|
|
// Indicate success.
|
|
|
|
bSuccess = TRUE;
|
|
}
|
|
__finally
|
|
{
|
|
// Free buffers.
|
|
|
|
if (pNewAcl != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)pNewAcl);
|
|
|
|
if (psd != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)psd);
|
|
|
|
if (psdNew != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)psdNew);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL GetLogonSIDOrUserSid(IN HANDLE hToken, OUT PSID *ppsid)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
DWORD dwIndex;
|
|
DWORD dwLength = 0;
|
|
PTOKEN_GROUPS ptg = NULL;
|
|
|
|
*ppsid = NULL;
|
|
|
|
// Get required buffer size and allocate the TOKEN_GROUPS buffer.
|
|
|
|
if (!GetTokenInformation(
|
|
hToken, // handle to the access token
|
|
TokenGroups, // get information about the token's groups
|
|
(PVOID) ptg, // pointer to TOKEN_GROUPS buffer
|
|
0, // size of buffer
|
|
&dwLength // receives required buffer size
|
|
))
|
|
{
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
goto Cleanup;
|
|
|
|
ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY, dwLength);
|
|
|
|
if (ptg == NULL)
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Get the token group information from the access token.
|
|
|
|
if (!GetTokenInformation(
|
|
hToken, // handle to the access token
|
|
TokenGroups, // get information about the token's groups
|
|
(PVOID) ptg, // pointer to TOKEN_GROUPS buffer
|
|
dwLength, // size of buffer
|
|
&dwLength // receives required buffer size
|
|
))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Loop through the groups to find the logon SID.
|
|
|
|
for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
|
|
if (0 != (ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID))
|
|
{
|
|
// Found the logon SID; make a copy of it.
|
|
|
|
dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
|
|
*ppsid = (PSID) HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY, dwLength);
|
|
if (*ppsid == NULL)
|
|
goto Cleanup;
|
|
if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)*ppsid);
|
|
goto Cleanup;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (NULL == *ppsid)
|
|
{
|
|
ULONG cbUserInfo;
|
|
PUCHAR pnSubAuthorityCount = 0;
|
|
CHAR UserInfoBuffer[4096] = {0};
|
|
PTOKEN_USER pUserInfo = (PTOKEN_USER) UserInfoBuffer;
|
|
|
|
SspiPrint(SSPI_WARN, TEXT("GetLogonSIDOrUserSid failed to find logon id, trying user sid\n"));
|
|
|
|
if (!GetTokenInformation(
|
|
hToken,
|
|
TokenUser,
|
|
UserInfoBuffer,
|
|
sizeof(UserInfoBuffer),
|
|
&cbUserInfo
|
|
))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!IsValidSid(pUserInfo->User.Sid)) goto Cleanup;
|
|
|
|
pnSubAuthorityCount = GetSidSubAuthorityCount(pUserInfo->User.Sid);
|
|
dwLength = GetSidLengthRequired(*pnSubAuthorityCount);
|
|
|
|
*ppsid = (PSID) HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY, dwLength);
|
|
if (*ppsid == NULL)
|
|
goto Cleanup;
|
|
|
|
if (!CopySid(dwLength, *ppsid, pUserInfo->User.Sid))
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)*ppsid);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
// Free the buffer for the token groups.
|
|
|
|
if (ptg != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)ptg);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
VOID FreeLogonSID(IN PSID *ppsid)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, (PVOID)*ppsid);
|
|
}
|
|
|
|
/**
|
|
This function builds a Dacl which grants the creator of the objects
|
|
FILE_ALL_ACCESS and Everyone FILE_GENERIC_READ and FILE_GENERIC_WRITE
|
|
access to the object.
|
|
|
|
This Dacl allows for higher security than a NULL Dacl, which is common for
|
|
named-pipes, as this only grants the creator/owner write access to the
|
|
security descriptor, and grants Everyone the ability to "use" the named-pipe.
|
|
This scenario prevents a malevolent user from disrupting service by preventing
|
|
arbitrary access manipulation.
|
|
**/
|
|
BOOL
|
|
BuildNamedPipeAcl(
|
|
IN OUT PACL pAcl,
|
|
OUT PDWORD pcbAclSize
|
|
)
|
|
{
|
|
DWORD cbAclSize = 0;
|
|
|
|
SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY siaCreator = SECURITY_CREATOR_SID_AUTHORITY;
|
|
|
|
BYTE BufEveryoneSid[32] = {0};
|
|
BYTE BufOwnerSid[32] = {0};
|
|
|
|
PSID pEveryoneSid = (PSID)BufEveryoneSid;
|
|
PSID pOwnerSid = (PSID)BufOwnerSid;
|
|
|
|
//
|
|
// compute size of acl
|
|
//
|
|
cbAclSize = sizeof(ACL) + 2 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) )
|
|
+ GetSidLengthRequired( 1 ) // well-known Everyone Sid
|
|
+ GetSidLengthRequired( 1 ) ; // well-known Creator Owner Sid
|
|
|
|
if (*pcbAclSize < cbAclSize)
|
|
{
|
|
*pcbAclSize = cbAclSize;
|
|
return FALSE;
|
|
}
|
|
|
|
*pcbAclSize = cbAclSize;
|
|
|
|
//
|
|
// intialize well known sids
|
|
//
|
|
|
|
if (!InitializeSid(pEveryoneSid, &siaWorld, 1)) return FALSE;
|
|
|
|
*GetSidSubAuthority(pEveryoneSid, 0) = SECURITY_WORLD_RID;
|
|
|
|
if (!InitializeSid(pOwnerSid, &siaCreator, 1)) return FALSE;
|
|
|
|
*GetSidSubAuthority(pOwnerSid, 0) = SECURITY_CREATOR_OWNER_RID;
|
|
|
|
if (!InitializeAcl(pAcl, cbAclSize, ACL_REVISION))
|
|
return FALSE;
|
|
|
|
if (!AddAccessAllowedAce(
|
|
pAcl,
|
|
ACL_REVISION,
|
|
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
|
|
pEveryoneSid
|
|
))
|
|
return FALSE;
|
|
|
|
return AddAccessAllowedAce(
|
|
pAcl,
|
|
ACL_REVISION,
|
|
FILE_ALL_ACCESS,
|
|
pOwnerSid
|
|
);
|
|
}
|
|
|