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.
1337 lines
32 KiB
1337 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
All rights reserved
|
|
|
|
Module Name:
|
|
|
|
lsasspi.cxx
|
|
|
|
Abstract:
|
|
|
|
lsasspi
|
|
|
|
Author:
|
|
|
|
Larry Zhu (LZhu) December 1, 2001 Created
|
|
|
|
Environment:
|
|
|
|
User Mode -Win32
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "lsasspi.hxx"
|
|
#include "dbgstate.hxx"
|
|
|
|
#define SECUR32DLL TEXT("secur32.dll")
|
|
|
|
PCSTR
|
|
LogonType2Str(
|
|
IN ULONG LogonType
|
|
)
|
|
{
|
|
static PCSTR g_cszLogonTypes[] =
|
|
{
|
|
"Invalid",
|
|
"Invalid",
|
|
"Interactive",
|
|
"Network",
|
|
"Batch",
|
|
"Service",
|
|
"Proxy",
|
|
"Unlock",
|
|
"NetworkCleartext",
|
|
"NewCredentials",
|
|
"RemoteInteractive", // Remote, yet interactive. Terminal server
|
|
"CachedInteractive",
|
|
};
|
|
|
|
return ((LogonType < COUNTOF(g_cszLogonTypes)) ?
|
|
g_cszLogonTypes[LogonType] : "Invalid");
|
|
}
|
|
|
|
PCSTR
|
|
ImpLevel2Str(
|
|
IN ULONG Level
|
|
)
|
|
{
|
|
static PCSTR ImpLevels[] = {
|
|
"Anonymous",
|
|
"Identification",
|
|
"Impersonation",
|
|
"Delegation"
|
|
};
|
|
return ((Level < COUNTOF(ImpLevels)) ? ImpLevels[Level] : "Illegal!");
|
|
}
|
|
|
|
NTSTATUS
|
|
GetLsaHandleAndPackageId(
|
|
IN PCSTR pszPackageNameA,
|
|
OUT HANDLE* pLsaHandle,
|
|
OUT ULONG* pPackageId
|
|
)
|
|
{
|
|
BOOLEAN bWasTcbPrivEnabled = FALSE;
|
|
BOOLEAN bIsImpersonating = TRUE;
|
|
|
|
return GetLsaHandleAndPackageIdEx(
|
|
pszPackageNameA,
|
|
pLsaHandle,
|
|
pPackageId,
|
|
&bWasTcbPrivEnabled,
|
|
&bIsImpersonating
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
GetLsaHandleAndPackageIdEx(
|
|
IN PCSTR pszPackageNameA,
|
|
OUT HANDLE* pLsaHandle,
|
|
OUT ULONG* pPackageId,
|
|
OUT BOOLEAN* pbWasTcbPrivEnabled,
|
|
OUT BOOLEAN* pbIsImpersonating
|
|
)
|
|
{
|
|
TNtStatus Status = STATUS_UNSUCCESSFUL;
|
|
|
|
STRING Name = {0};
|
|
LSA_OPERATIONAL_MODE Ignored = 0;
|
|
HANDLE LogonHandle = NULL;
|
|
ULONG PackageId = -1;
|
|
BOOLEAN bIsImpersonating = TRUE;
|
|
DWORD UserInfoResponseLength = 0;
|
|
|
|
DebugPrintf(SSPI_LOG, "GetLsaHandleAndPackageId looking for %s\n", pszPackageNameA);
|
|
|
|
*pLsaHandle = NULL;
|
|
*pPackageId = -1;
|
|
|
|
//
|
|
// Turn on the TCB privilege
|
|
//
|
|
|
|
DBGCFG2(Status, STATUS_PRIVILEGE_NOT_HELD, STATUS_NO_TOKEN);
|
|
|
|
Status DBGCHK = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, *pbIsImpersonating, pbWasTcbPrivEnabled);
|
|
|
|
if (STATUS_NO_TOKEN == (NTSTATUS) Status)
|
|
{
|
|
*pbIsImpersonating = FALSE;
|
|
Status DBGCHK = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, *pbIsImpersonating, pbWasTcbPrivEnabled);
|
|
}
|
|
else if (!NT_SUCCESS(Status))
|
|
{
|
|
*pbIsImpersonating = TRUE;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
RtlInitString(
|
|
&Name,
|
|
"SspTest"
|
|
);
|
|
Status DBGCHK = LsaRegisterLogonProcess(
|
|
&Name,
|
|
&LogonHandle,
|
|
&Ignored
|
|
);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DebugPrintf(SSPI_LOG, "LsaRegisterLogonProcess succeeded\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status DBGCHK = LsaConnectUntrusted(&LogonHandle);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DebugPrintf(SSPI_LOG, "LsaConnectUntrusted succeeded\n");
|
|
}
|
|
}
|
|
|
|
RtlInitString(
|
|
&Name,
|
|
pszPackageNameA
|
|
);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status DBGCHK = LsaLookupAuthenticationPackage(
|
|
LogonHandle,
|
|
&Name,
|
|
&PackageId
|
|
);
|
|
}
|
|
|
|
*pPackageId = PackageId;
|
|
*pLsaHandle = LogonHandle;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
FindAndOpenWinlogon(
|
|
OUT HANDLE* phWinlogon
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
|
|
HANDLE hWinlogon = NULL;
|
|
SYSTEM_PROCESS_INFORMATION* pSystemInfo = NULL;
|
|
SYSTEM_PROCESS_INFORMATION* pWalk = NULL;
|
|
OBJECT_ATTRIBUTES Obja = {0};
|
|
CLIENT_ID ClientId = {0};
|
|
|
|
UNICODE_STRING Winlogon = CONSTANT_UNICODE_STRING(L"winlogon.exe");
|
|
|
|
pSystemInfo = (SYSTEM_PROCESS_INFORMATION*) new CHAR[sizeof(SYSTEM_PROCESS_INFORMATION) * 1024];
|
|
|
|
Status DBGCHK = pSystemInfo ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status DBGCHK = NtQuerySystemInformation(
|
|
SystemProcessInformation,
|
|
pSystemInfo,
|
|
sizeof(SYSTEM_PROCESS_INFORMATION) * 1024,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
pWalk = pSystemInfo ;
|
|
|
|
while (RtlCompareUnicodeString(&pWalk->ImageName, &Winlogon, TRUE) != 0)
|
|
{
|
|
if (pWalk->NextEntryOffset == 0)
|
|
{
|
|
pWalk = NULL ;
|
|
break;
|
|
}
|
|
|
|
pWalk = (SYSTEM_PROCESS_INFORMATION*) ((UCHAR*) pWalk + pWalk->NextEntryOffset);
|
|
}
|
|
|
|
Status DBGCHK = pWalk ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
ClientId.UniqueThread = (HANDLE)NULL;
|
|
ClientId.UniqueProcess = (HANDLE)LongToHandle(PtrToUlong(pWalk->UniqueProcessId));
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
NULL,
|
|
0, // (bInheritHandle ? OBJ_INHERIT : 0),
|
|
NULL,
|
|
NULL
|
|
);
|
|
Status DBGCHK = NtOpenProcess(
|
|
&hWinlogon,
|
|
(ACCESS_MASK)PROCESS_QUERY_INFORMATION,
|
|
&Obja,
|
|
&ClientId
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*phWinlogon = hWinlogon;
|
|
hWinlogon = NULL;
|
|
}
|
|
|
|
if (pSystemInfo)
|
|
{
|
|
delete [] pSystemInfo;
|
|
}
|
|
|
|
if (hWinlogon)
|
|
{
|
|
NtClose(hWinlogon);
|
|
}
|
|
|
|
return Status ;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetSystemToken(
|
|
OUT HANDLE* phSystemToken
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
|
|
HANDLE hWinlogon = NULL;
|
|
|
|
Status DBGCHK = FindAndOpenWinlogon(&hWinlogon);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status DBGCHK = GetProcessToken(hWinlogon, phSystemToken);
|
|
}
|
|
|
|
if (hWinlogon)
|
|
{
|
|
NtClose(hWinlogon);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Impersonate(
|
|
IN OPTIONAL HANDLE hToken
|
|
)
|
|
{
|
|
TNtStatus Status = STATUS_SUCCESS;
|
|
|
|
TOKEN_TYPE Type;
|
|
ULONG cbType;
|
|
HANDLE hImpToken = NULL;
|
|
HANDLE hDupToken = NULL;
|
|
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
if (hToken)
|
|
{
|
|
Status DBGCHK = NtQueryInformationToken(
|
|
hToken,
|
|
TokenType,
|
|
&Type,
|
|
sizeof(TOKEN_TYPE),
|
|
&cbType
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (Type == TokenPrimary)
|
|
{
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
NULL,
|
|
0L,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
|
|
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
SecurityQualityOfService.EffectiveOnly = FALSE;
|
|
|
|
ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
|
|
|
|
Status DBGCHK = NtDuplicateToken(
|
|
hToken,
|
|
TOKEN_IMPERSONATE | TOKEN_QUERY,
|
|
&ObjectAttributes,
|
|
FALSE,
|
|
TokenImpersonation,
|
|
&hDupToken
|
|
);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
hImpToken = hDupToken;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hImpToken = hToken;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status DBGCHK = NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
&hImpToken,
|
|
sizeof(hImpToken)
|
|
);
|
|
}
|
|
|
|
if (hDupToken)
|
|
{
|
|
NtClose(hDupToken);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
HRESULT
|
|
GetProcessToken(
|
|
IN HANDLE hProcess,
|
|
OUT HANDLE* phProcessToken
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
|
|
HANDLE hProcessToken = NULL;
|
|
HANDLE hSubToken = NULL;
|
|
HANDLE hDupToken = NULL;
|
|
SECURITY_DESCRIPTOR SdNullDACL = {0};
|
|
SECURITY_DESCRIPTOR* pSave = NULL;
|
|
ULONG cbSdSize = 0;
|
|
BOOLEAN bNeedRestoreSd = FALSE;
|
|
|
|
DBGCFG1(hRetval, HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
|
|
|
|
hRetval DBGCHK = OpenProcessToken(
|
|
hProcess,
|
|
TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE,
|
|
&hProcessToken
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (FAILED(hRetval) && (HRESULT_CODE(hRetval) == ERROR_ACCESS_DENIED))
|
|
{
|
|
SspiPrint(SSPI_WARN,
|
|
TEXT("GetProcessToken failed with access denied to get token for process %p\n"),
|
|
hProcess);
|
|
hRetval DBGCHK = OpenProcessToken(
|
|
hProcess,
|
|
READ_CONTROL | WRITE_DAC,
|
|
&hSubToken
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
cbSdSize = 1024;
|
|
pSave = (SECURITY_DESCRIPTOR*) new CHAR[cbSdSize];
|
|
|
|
hRetval DBGCHK = pSave ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = GetKernelObjectSecurity(
|
|
hSubToken,
|
|
DACL_SECURITY_INFORMATION,
|
|
pSave,
|
|
cbSdSize,
|
|
&cbSdSize
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (FAILED(hRetval) && (ERROR_INSUFFICIENT_BUFFER == HRESULT_CODE(hRetval)))
|
|
{
|
|
delete [] pSave;
|
|
|
|
pSave = (SECURITY_DESCRIPTOR*) new CHAR[cbSdSize];
|
|
|
|
hRetval DBGCHK = pSave ? S_OK : E_OUTOFMEMORY;
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = GetKernelObjectSecurity(
|
|
hSubToken,
|
|
DACL_SECURITY_INFORMATION,
|
|
pSave,
|
|
cbSdSize,
|
|
&cbSdSize
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
bNeedRestoreSd = TRUE;
|
|
|
|
hRetval DBGCHK = InitializeSecurityDescriptor(&SdNullDACL, SECURITY_DESCRIPTOR_REVISION) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = SetSecurityDescriptorDacl(&SdNullDACL, TRUE, NULL, FALSE) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = SetKernelObjectSecurity(
|
|
hSubToken,
|
|
DACL_SECURITY_INFORMATION,
|
|
&SdNullDACL
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = OpenProcessToken(
|
|
hProcess,
|
|
TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE,
|
|
&hProcessToken
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = DuplicateTokenEx(
|
|
hProcessToken,
|
|
MAXIMUM_ALLOWED,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenPrimary,
|
|
&hDupToken
|
|
);
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
*phProcessToken = hDupToken;
|
|
hDupToken = NULL;
|
|
}
|
|
|
|
if (hSubToken)
|
|
{
|
|
CloseHandle(hSubToken);
|
|
}
|
|
|
|
if (hDupToken)
|
|
{
|
|
CloseHandle(hDupToken);
|
|
}
|
|
|
|
if (hProcessToken)
|
|
{
|
|
CloseHandle(hProcessToken);
|
|
}
|
|
|
|
if (bNeedRestoreSd)
|
|
{
|
|
SetKernelObjectSecurity(
|
|
hSubToken,
|
|
DACL_SECURITY_INFORMATION,
|
|
pSave
|
|
);
|
|
}
|
|
|
|
if (pSave)
|
|
{
|
|
delete [] pSave;
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
HRESULT
|
|
GetProcessTokenWithNullDACL(
|
|
IN HANDLE hProcess,
|
|
OUT HANDLE* phProcessToken
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
|
|
HANDLE hProcessToken = NULL;
|
|
HANDLE hSubToken = NULL;
|
|
HANDLE hDupToken = NULL;
|
|
SECURITY_DESCRIPTOR SdNullDACL = {0};
|
|
|
|
hRetval DBGCHK = OpenProcessToken(
|
|
hProcess,
|
|
READ_CONTROL | WRITE_DAC,
|
|
&hSubToken
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = InitializeSecurityDescriptor(&SdNullDACL, SECURITY_DESCRIPTOR_REVISION) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = SetSecurityDescriptorDacl(&SdNullDACL, TRUE, NULL, FALSE) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = SetKernelObjectSecurity(
|
|
hSubToken,
|
|
DACL_SECURITY_INFORMATION,
|
|
&SdNullDACL
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = OpenProcessToken(
|
|
hProcess,
|
|
TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE,
|
|
&hProcessToken
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = DuplicateTokenEx(
|
|
hProcessToken,
|
|
MAXIMUM_ALLOWED,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenPrimary,
|
|
&hDupToken
|
|
);
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
*phProcessToken = hDupToken;
|
|
hDupToken = NULL;
|
|
}
|
|
|
|
if (hSubToken)
|
|
{
|
|
CloseHandle(hSubToken);
|
|
}
|
|
|
|
if (hDupToken)
|
|
{
|
|
CloseHandle(hDupToken);
|
|
}
|
|
|
|
if (hProcessToken)
|
|
{
|
|
CloseHandle(hProcessToken);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
HRESULT
|
|
CreateProcessAsUserEx(
|
|
IN HANDLE hToken,
|
|
IN UNICODE_STRING* pApplication
|
|
)
|
|
{
|
|
THResult hRetval = S_OK;
|
|
|
|
PROCESS_INFORMATION pi = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0};
|
|
STARTUPINFOW si = {0};
|
|
|
|
HANDLE hTokenNew = NULL;
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
DBGCFG1(hRetval, HRESULT_FROM_WIN32(ERROR_BAD_TOKEN_TYPE));
|
|
|
|
DebugPrintf(SSPI_LOG, "CreateProcessAsUserEx hTokenNew %p, Application %wZ\n", hToken, pApplication);
|
|
|
|
hRetval DBGCHK = CreateProcessAsUserW(
|
|
hToken,
|
|
NULL,
|
|
pApplication->Buffer,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (FAILED(hRetval) && (ERROR_BAD_TOKEN_TYPE == HRESULT_CODE(hRetval)))
|
|
{
|
|
DebugPrintf(SSPI_WARN, "CreateProcessAsUserW failed with ERROR_BAD_TOKEN_TYPE\n");
|
|
|
|
hRetval DBGCHK = DuplicateTokenEx(
|
|
hToken,
|
|
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenPrimary,
|
|
&hTokenNew
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = CreateProcessAsUserW(
|
|
hTokenNew,
|
|
NULL,
|
|
pApplication->Buffer,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
}
|
|
|
|
if (hTokenNew)
|
|
{
|
|
CloseHandle(hTokenNew);
|
|
}
|
|
|
|
if (pi.hProcess != INVALID_HANDLE_VALUE)
|
|
{
|
|
// WaitForSingleObject(pi.hProcess, INFINITE);
|
|
CloseHandle(pi.hProcess);
|
|
}
|
|
|
|
if (pi.hThread != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(pi.hThread);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
NTSTATUS
|
|
CheckUserToken(
|
|
IN HANDLE hToken
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
|
|
TOKEN_STATISTICS TokenStat = {0};
|
|
CHAR Buff[sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE] = {0};
|
|
TOKEN_USER* pTokenUserData = (TOKEN_USER*) Buff;
|
|
|
|
ULONG cbReturnLength = 0;
|
|
PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
|
|
|
|
Status DBGCHK = NtQueryInformationToken(
|
|
hToken,
|
|
TokenStatistics,
|
|
&TokenStat,
|
|
sizeof(TokenStat),
|
|
&cbReturnLength
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DebugPrintf(SSPI_LOG, "LogonId %#x:%#x, Impersonation Level %s, TokenType %s\n",
|
|
TokenStat.AuthenticationId.HighPart,
|
|
TokenStat.AuthenticationId.LowPart,
|
|
ImpLevel2Str(TokenStat.ImpersonationLevel),
|
|
TokenStat.TokenType == TokenPrimary ? "Primary" : "Impersonation");
|
|
|
|
Status DBGCHK = LsaGetLogonSessionData(&TokenStat.AuthenticationId, &pLogonSessionData);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DebugPrintLogonSessionData(SSPI_LOG, pLogonSessionData);
|
|
}
|
|
else if ( (STATUS_NO_SUCH_LOGON_SESSION == (NTSTATUS) Status)
|
|
|| (STATUS_ACCESS_DENIED == (NTSTATUS) Status) )
|
|
{
|
|
Status DBGCHK = NtQueryInformationToken(
|
|
hToken,
|
|
TokenUser,
|
|
Buff,
|
|
sizeof(Buff),
|
|
&cbReturnLength
|
|
);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DebugPrintSidFriendlyName(SSPI_LOG, "Sid", pTokenUserData->User.Sid);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pLogonSessionData)
|
|
{
|
|
LsaFreeReturnBuffer(pLogonSessionData);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
HRESULT
|
|
CheckUserData(
|
|
VOID
|
|
)
|
|
{
|
|
THResult hRetval = E_FAIL;
|
|
|
|
TOKEN_STATISTICS TokenStat = {0};
|
|
ULONG cbReturnLength = 0;
|
|
PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
|
|
HANDLE hNullToken = NULL;
|
|
HANDLE hToken = NULL;
|
|
BOOL bIsImpersonating = FALSE;
|
|
|
|
hRetval DBGCHK = NtOpenThreadToken(
|
|
NtCurrentThread(), // handle to thread
|
|
MAXIMUM_ALLOWED, // access to process
|
|
TRUE, // process or thread security
|
|
&hToken // handle to open access token
|
|
);
|
|
|
|
if (STATUS_NO_TOKEN == (HRESULT) hRetval)
|
|
{
|
|
hRetval DBGCHK = NtOpenProcessToken(
|
|
NtCurrentProcess(), // handle to process
|
|
MAXIMUM_ALLOWED, // access to process
|
|
&hToken // handle to open access token
|
|
);
|
|
}
|
|
else if (SUCCEEDED(hRetval))
|
|
{
|
|
bIsImpersonating = TRUE;
|
|
}
|
|
|
|
//
|
|
// Revert to self
|
|
//
|
|
|
|
if (SUCCEEDED(hRetval) && bIsImpersonating)
|
|
{
|
|
hRetval DBGCHK = NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
&hNullToken,
|
|
sizeof( HANDLE )
|
|
);
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = CheckUserToken(hToken);
|
|
}
|
|
|
|
//
|
|
// restore thread token
|
|
//
|
|
|
|
if (bIsImpersonating)
|
|
{
|
|
TNtStatus hr;
|
|
|
|
hr DBGCHK = NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
&hToken,
|
|
sizeof( HANDLE )
|
|
);
|
|
if (SUCCEEDED(hRetval) && FAILED(hr))
|
|
{
|
|
hRetval DBGNOCHK = hr;
|
|
}
|
|
}
|
|
|
|
if (pLogonSessionData)
|
|
{
|
|
LsaFreeReturnBuffer(pLogonSessionData);
|
|
}
|
|
|
|
if (hToken)
|
|
{
|
|
NtClose(hToken);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetProcessHandleByCid(
|
|
IN ULONG ProcessID,
|
|
OUT HANDLE* phProcess
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
|
|
HANDLE hProcess = NULL;
|
|
CLIENT_ID ClientId = {0};
|
|
OBJECT_ATTRIBUTES Obja = {0};
|
|
|
|
SspiPrint(SSPI_LOG, TEXT("GetProcessHandleByCid %#x(%d)\n"), ProcessID, ProcessID);
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
ClientId.UniqueProcess = LongToHandle(ProcessID);
|
|
ClientId.UniqueThread = NULL;
|
|
|
|
Status DBGCHK = NtOpenProcess(
|
|
&hProcess,
|
|
PROCESS_QUERY_INFORMATION,
|
|
&Obja,
|
|
&ClientId
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*phProcess = hProcess;
|
|
hProcess = NULL;
|
|
}
|
|
|
|
if (hProcess)
|
|
{
|
|
NtClose(hProcess);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
HRESULT
|
|
GetProcessTokenByProcessId(
|
|
IN ULONG ProcessID,
|
|
OUT HANDLE* phToken
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
HANDLE hProcess = NULL;
|
|
HANDLE hToken = NULL;
|
|
|
|
SspiPrint(SSPI_LOG, TEXT("GetProcessTokenByProcessId: ProcessID %#x(%d)\n"), ProcessID, ProcessID);
|
|
|
|
hProcess = OpenProcess(
|
|
PROCESS_QUERY_INFORMATION,
|
|
FALSE,
|
|
ProcessID
|
|
);
|
|
|
|
hRetval DBGCHK = hProcess ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = GetProcessToken(hProcess, &hToken);
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
*phToken = hToken;
|
|
hToken = NULL;
|
|
}
|
|
|
|
if (hProcess)
|
|
{
|
|
CloseHandle(hProcess);
|
|
}
|
|
|
|
if (hToken)
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
PCSTR
|
|
GetSidTypeStr(
|
|
IN SID_NAME_USE eUse
|
|
)
|
|
{
|
|
static PCSTR acszSidTypeStr[] =
|
|
{
|
|
"Invalid", "User", "Group", "Domain", "Alias", "Well Known Group",
|
|
"Deleted Account", "Invalid", "Unknown", "Computer",
|
|
};
|
|
|
|
if (eUse < SidTypeUser || eUse > SidTypeComputer)
|
|
{
|
|
throw "Unrecognized SID";
|
|
}
|
|
|
|
return acszSidTypeStr[eUse];
|
|
}
|
|
|
|
VOID
|
|
DebugPrintSidFriendlyName(
|
|
IN ULONG Level,
|
|
IN PCSTR pszBanner,
|
|
IN PSID pSid
|
|
)
|
|
{
|
|
TNtStatus NtStatus;
|
|
|
|
UNICODE_STRING ucsSid = {0};
|
|
|
|
NtStatus DBGCHK = RtlConvertSidToUnicodeString(&ucsSid, pSid, TRUE);
|
|
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
THResult hRetval = E_FAIL;
|
|
|
|
CHAR szName[MAX_PATH] = {0};
|
|
CHAR szDomainName[MAX_PATH] ={0};
|
|
SID_NAME_USE eUse = SidTypeInvalid;
|
|
DWORD cbName = sizeof(szName) - 1;
|
|
DWORD cbDomainName = sizeof(szDomainName) - 1;
|
|
|
|
DBGCFG1(hRetval, HRESULT_FROM_WIN32(ERROR_NONE_MAPPED));
|
|
|
|
hRetval DBGCHK = LookupAccountSidA(
|
|
NULL,
|
|
pSid,
|
|
szName,
|
|
&cbName,
|
|
szDomainName,
|
|
&cbDomainName,
|
|
&eUse
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
DebugPrintf(Level, "%s %wZ -> (%s: %s\\%s)\n",
|
|
pszBanner,
|
|
&ucsSid,
|
|
GetSidTypeStr(eUse),
|
|
*szDomainName ? szDomainName : "localhost", szName);
|
|
}
|
|
else if (FAILED(hRetval) && (ERROR_NONE_MAPPED == HRESULT_CODE(hRetval)))
|
|
{
|
|
DebugPrintf(SSPI_LOG, "%s %wZ -> (no name mapped)\n", pszBanner,&ucsSid);
|
|
}
|
|
}
|
|
|
|
RtlFreeUnicodeString(&ucsSid);
|
|
}
|
|
|
|
VOID
|
|
DebugPrintLogonSessionData(
|
|
IN ULONG Level,
|
|
IN SECURITY_LOGON_SESSION_DATA* pLogonSessionData
|
|
)
|
|
{
|
|
if (pLogonSessionData && (pLogonSessionData->Size >= sizeof(SECURITY_LOGON_SESSION_DATA_OLD)))
|
|
{
|
|
DebugPrintf(Level, "LogonSession Data for LogonId %#x:%#x\n", pLogonSessionData->LogonId.HighPart, pLogonSessionData->LogonId.HighPart);
|
|
DebugPrintf(Level, "UserName %wZ\n", &pLogonSessionData->UserName);
|
|
DebugPrintf(Level, "LogonDomain %wZ\n", &pLogonSessionData->LogonDomain);
|
|
DebugPrintf(Level, "AuthenticationPackage %wZ\n", &pLogonSessionData->AuthenticationPackage);
|
|
DebugPrintf(Level, "LogonType %#x (%s)\n", pLogonSessionData->LogonType, LogonType2Str(pLogonSessionData->LogonType));
|
|
DebugPrintf(Level, "Session %#x\n", pLogonSessionData->Session);
|
|
DebugPrintSidFriendlyName(Level, "Sid", pLogonSessionData->Sid);
|
|
DebugPrintSysTimeAsLocalTime(Level, "LogonTime", &pLogonSessionData->LogonTime);
|
|
|
|
if (pLogonSessionData->Size >= sizeof(SECURITY_LOGON_SESSION_DATA))
|
|
{
|
|
DebugPrintf(Level, "LogonServer %wZ\n", &pLogonSessionData->LogonServer);
|
|
DebugPrintf(Level, "DnsDomainName %wZ\n", &pLogonSessionData->DnsDomainName);
|
|
DebugPrintf(Level, "Upn %wZ\n", &pLogonSessionData->Upn);
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
LsaGetLogonSessionData(
|
|
IN PLUID LogonId,
|
|
OUT PSECURITY_LOGON_SESSION_DATA * ppLogonSessionData
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
PFuncLsaGetLogonSessionData pFuncLsaGetLogonSessionData = NULL;
|
|
|
|
HMODULE hLib = LoadLibrary(SECUR32DLL);
|
|
|
|
hRetval DBGCHK = hLib ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
pFuncLsaGetLogonSessionData =
|
|
(PFuncLsaGetLogonSessionData) GetProcAddress(hLib, "LsaGetLogonSessionData");
|
|
hRetval DBGCHK = pFuncLsaGetLogonSessionData ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = (*pFuncLsaGetLogonSessionData)(LogonId, ppLogonSessionData);
|
|
}
|
|
|
|
if (hLib)
|
|
{
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
NTSTATUS
|
|
LsaRegisterLogonProcess (
|
|
IN PLSA_STRING LogonProcessName,
|
|
OUT PHANDLE LsaHandle,
|
|
OUT PLSA_OPERATIONAL_MODE SecurityMode
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
PFuncLsaRegisterLogonProcess pFuncLsaRegisterLogonProcess = NULL;
|
|
|
|
HMODULE hLib = LoadLibrary(SECUR32DLL);
|
|
|
|
hRetval DBGCHK = hLib ? S_OK : GetLastErrorAsHResult();
|
|
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
pFuncLsaRegisterLogonProcess =
|
|
(PFuncLsaRegisterLogonProcess) GetProcAddress(hLib, "LsaRegisterLogonProcess");
|
|
hRetval DBGCHK = pFuncLsaRegisterLogonProcess ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = (*pFuncLsaRegisterLogonProcess)(LogonProcessName, LsaHandle, SecurityMode);
|
|
}
|
|
|
|
if (hLib)
|
|
{
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
NTSTATUS
|
|
LsaLookupAuthenticationPackage(
|
|
IN HANDLE LsaHandle,
|
|
IN PLSA_STRING PackageName,
|
|
OUT PULONG AuthenticationPackage
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
PFuncLsaLookupAuthenticationPackage pFuncLsaLookupAuthenticationPackage = NULL;
|
|
|
|
HMODULE hLib = LoadLibrary(SECUR32DLL);
|
|
|
|
hRetval DBGCHK = hLib ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
pFuncLsaLookupAuthenticationPackage =
|
|
(PFuncLsaLookupAuthenticationPackage) GetProcAddress(hLib, "LsaLookupAuthenticationPackage");
|
|
hRetval DBGCHK = pFuncLsaLookupAuthenticationPackage ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = (*pFuncLsaLookupAuthenticationPackage)(LsaHandle, PackageName, AuthenticationPackage);
|
|
}
|
|
|
|
if (hLib)
|
|
{
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
NTSTATUS
|
|
LsaLogonUser(
|
|
IN HANDLE LsaHandle,
|
|
IN PLSA_STRING OriginName,
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN ULONG AuthenticationPackage,
|
|
IN PVOID AuthenticationInformation,
|
|
IN ULONG AuthenticationInformationLength,
|
|
IN PTOKEN_GROUPS LocalGroups OPTIONAL,
|
|
IN PTOKEN_SOURCE SourceContext,
|
|
OUT PVOID *ProfileBuffer,
|
|
OUT PULONG ProfileBufferLength,
|
|
OUT PLUID LogonId,
|
|
OUT PHANDLE Token,
|
|
OUT PQUOTA_LIMITS Quotas,
|
|
OUT PNTSTATUS SubStatus
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
PFuncLsaLogonUser pFuncLsaLogonUser = NULL;
|
|
|
|
HMODULE hLib = LoadLibrary(SECUR32DLL);
|
|
|
|
hRetval DBGCHK = hLib ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
pFuncLsaLogonUser =
|
|
(PFuncLsaLogonUser) GetProcAddress(hLib, "LsaLogonUser");
|
|
hRetval DBGCHK = pFuncLsaLogonUser ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = (*pFuncLsaLogonUser)(
|
|
LsaHandle,
|
|
OriginName,
|
|
LogonType,
|
|
AuthenticationPackage,
|
|
AuthenticationInformation,
|
|
AuthenticationInformationLength,
|
|
LocalGroups,
|
|
SourceContext,
|
|
ProfileBuffer,
|
|
ProfileBufferLength,
|
|
LogonId,
|
|
Token,
|
|
Quotas,
|
|
SubStatus
|
|
);
|
|
}
|
|
|
|
if (hLib)
|
|
{
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
NTSTATUS
|
|
LsaFreeReturnBuffer(
|
|
IN PVOID Buffer
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
PFuncLsaFreeReturnBuffer pFuncLsaFreeReturnBuffer = NULL;
|
|
|
|
HMODULE hLib = LoadLibrary(SECUR32DLL);
|
|
|
|
hRetval DBGCHK = hLib ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
pFuncLsaFreeReturnBuffer =
|
|
(PFuncLsaFreeReturnBuffer) GetProcAddress(hLib, "LsaFreeReturnBuffer");
|
|
hRetval DBGCHK = pFuncLsaFreeReturnBuffer ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = (*pFuncLsaFreeReturnBuffer)(Buffer);
|
|
}
|
|
|
|
if (hLib)
|
|
{
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
NTSTATUS
|
|
LsaConnectUntrusted(
|
|
OUT PHANDLE LsaHandle
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
PFuncLsaConnectUntrusted pFuncLsaConnectUntrusted = NULL;
|
|
|
|
HMODULE hLib = LoadLibrary(SECUR32DLL);
|
|
|
|
hRetval DBGCHK = hLib ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
pFuncLsaConnectUntrusted =
|
|
(PFuncLsaConnectUntrusted) GetProcAddress(hLib, "LsaConnectUntrusted");
|
|
hRetval DBGCHK = pFuncLsaConnectUntrusted ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = (*pFuncLsaConnectUntrusted)(LsaHandle);
|
|
}
|
|
|
|
if (hLib)
|
|
{
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
NTSTATUS
|
|
LsaDeregisterLogonProcess(
|
|
IN HANDLE LsaHandle
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
PFuncLsaDeregisterLogonProcess pFuncLsaDeregisterLogonProcess = NULL;
|
|
|
|
HMODULE hLib = LoadLibrary(SECUR32DLL);
|
|
|
|
hRetval DBGCHK = hLib ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
pFuncLsaDeregisterLogonProcess =
|
|
(PFuncLsaDeregisterLogonProcess) GetProcAddress(hLib, "LsaDeregisterLogonProcess");
|
|
hRetval DBGCHK = pFuncLsaDeregisterLogonProcess ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = (*pFuncLsaDeregisterLogonProcess)(LsaHandle);
|
|
}
|
|
|
|
if (hLib)
|
|
{
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
NTSTATUS
|
|
LsaCallAuthenticationPackage(
|
|
IN HANDLE LsaHandle,
|
|
IN ULONG AuthenticationPackage,
|
|
IN PVOID ProtocolSubmitBuffer,
|
|
IN ULONG SubmitBufferLength,
|
|
OUT PVOID* ProtocolReturnBuffer,
|
|
OUT PULONG ReturnBufferLength,
|
|
OUT PNTSTATUS ProtocolStatus
|
|
)
|
|
{
|
|
THResult hRetval;
|
|
PFuncLsaCallAuthenticationPackage pFuncLsaCallAuthenticationPackage = NULL;
|
|
|
|
HMODULE hLib = LoadLibrary(SECUR32DLL);
|
|
|
|
hRetval DBGCHK = hLib ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
pFuncLsaCallAuthenticationPackage =
|
|
(PFuncLsaCallAuthenticationPackage) GetProcAddress(hLib, "LsaCallAuthenticationPackage");
|
|
hRetval DBGCHK = pFuncLsaCallAuthenticationPackage ? S_OK : GetLastErrorAsHResult();
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval DBGCHK = (*pFuncLsaCallAuthenticationPackage)(
|
|
LsaHandle,
|
|
AuthenticationPackage,
|
|
ProtocolSubmitBuffer,
|
|
SubmitBufferLength,
|
|
ProtocolReturnBuffer,
|
|
ReturnBufferLength,
|
|
ProtocolStatus
|
|
);
|
|
}
|
|
|
|
if (hLib)
|
|
{
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
FARPROC
|
|
WINAPI
|
|
DelayLoadFailureHook (
|
|
LPCSTR pszDllName,
|
|
LPCSTR pszProcName
|
|
)
|
|
{
|
|
SspiPrint(SSPI_ERROR, TEXT("pszDllName %s, pszProcName %s\n"), pszDllName, pszProcName);
|
|
return NULL; // fool compiler
|
|
}
|
|
|
|
|