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.
1289 lines
38 KiB
1289 lines
38 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
logon.cxx
|
|
|
|
Abstract:
|
|
|
|
logon
|
|
|
|
Author:
|
|
|
|
Larry Zhu (LZhu) December 1, 2001 Created
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "logon.hxx"
|
|
|
|
NTSTATUS
|
|
LogonUserWrapper(
|
|
IN PCWSTR pszUserName,
|
|
IN PCWSTR pszDomainName,
|
|
IN PCWSTR pszPassword,
|
|
IN DWORD LogonType,
|
|
IN DWORD dwLogonProvider,
|
|
OUT HANDLE* phToken
|
|
)
|
|
{
|
|
THResult hResult = S_OK;
|
|
|
|
PSID pLoginSid = NULL;
|
|
VOID* pProfile = NULL;
|
|
ULONG cbProfile = 0;
|
|
QUOTA_LIMITS Quotas = {0};
|
|
|
|
DebugPrintf(SSPI_LOG, "LogonUserWrapper UserName %ws, DomainName %ws, Password %ws, LogonType %#x, Provider %#x\n",
|
|
pszUserName, pszDomainName, pszPassword, LogonType, dwLogonProvider);
|
|
|
|
hResult DBGCHK = LogonUserExW(
|
|
(PWSTR) pszUserName,
|
|
(PWSTR) pszDomainName,
|
|
(PWSTR) pszPassword,
|
|
LogonType,
|
|
dwLogonProvider,
|
|
phToken,
|
|
&pLoginSid,
|
|
&pProfile,
|
|
&cbProfile,
|
|
&Quotas
|
|
) ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
DebugPrintSidFriendlyName(SSPI_LOG, "LogonSid:", pLoginSid);
|
|
DebugPrintProfileAndQuotas(SSPI_LOG, pProfile, &Quotas);
|
|
|
|
DebugPrintf(SSPI_LOG, "LogonUserWrapper TokenHandle %p\n", *phToken);
|
|
}
|
|
|
|
if (pLoginSid)
|
|
{
|
|
LsaFreeReturnBuffer(pLoginSid);
|
|
}
|
|
|
|
if (pProfile)
|
|
{
|
|
LsaFreeReturnBuffer(pProfile);
|
|
}
|
|
|
|
return SUCCEEDED(hResult) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
VOID
|
|
DebugPrintProfileAndQuotas(
|
|
IN ULONG Level,
|
|
IN OPTIONAL VOID* pProfile,
|
|
IN OPTIONAL QUOTA_LIMITS* pQuotas
|
|
)
|
|
{
|
|
|
|
if (pQuotas)
|
|
{
|
|
DebugPrintf(Level, "Quotas PagedPoolLimit %p, NonPagedPoolLimit %p, "
|
|
"MinimumWorkingSetSize %p, MaximumWorkingSetSize %p, PagedPoolLimit %p\n",
|
|
pQuotas->PagedPoolLimit, pQuotas->NonPagedPoolLimit,
|
|
pQuotas->MinimumWorkingSetSize, pQuotas->MaximumWorkingSetSize,
|
|
pQuotas->PagedPoolLimit);
|
|
DebugPrintSysTimeAsLocalTime(Level, "TimeLimit", &pQuotas->TimeLimit);
|
|
}
|
|
|
|
if (pProfile)
|
|
{
|
|
if (MsV1_0InteractiveProfile == *((ULONG*) pProfile))
|
|
{
|
|
MSV1_0_INTERACTIVE_PROFILE* pMsvInteractiveProfile = (MSV1_0_INTERACTIVE_PROFILE*) pProfile;
|
|
DebugPrintf(Level, "MsV1_0InteractiveProfile: "
|
|
"LogonCount %#x, BadPasswordCount %#x, LogonScript %wZ, "
|
|
"HomeDirectory %wZ, FullName %wZ, ProfilePath %wZ, "
|
|
"HomeDriectoryDrive %wZ, LogonServer %wZ, UserFlags %#x\n",
|
|
pMsvInteractiveProfile->LogonCount,
|
|
pMsvInteractiveProfile->BadPasswordCount,
|
|
&pMsvInteractiveProfile->LogonScript,
|
|
&pMsvInteractiveProfile->HomeDirectory,
|
|
&pMsvInteractiveProfile->FullName,
|
|
&pMsvInteractiveProfile->ProfilePath,
|
|
&pMsvInteractiveProfile->HomeDirectoryDrive,
|
|
&pMsvInteractiveProfile->LogonServer,
|
|
pMsvInteractiveProfile->UserFlags);
|
|
DebugPrintSysTimeAsLocalTime(Level, "LogonTime", &pMsvInteractiveProfile->LogonTime);
|
|
DebugPrintSysTimeAsLocalTime(Level, "LogoffTime", &pMsvInteractiveProfile->LogoffTime);
|
|
DebugPrintSysTimeAsLocalTime(Level, "KickOffTime", &pMsvInteractiveProfile->KickOffTime );
|
|
DebugPrintSysTimeAsLocalTime(Level, "PasswordLastSet", &pMsvInteractiveProfile->PasswordLastSet );
|
|
DebugPrintSysTimeAsLocalTime(Level, "PasswordCanChange", &pMsvInteractiveProfile->PasswordCanChange );
|
|
DebugPrintSysTimeAsLocalTime(Level, "PasswordMustChange", &pMsvInteractiveProfile->PasswordMustChange );
|
|
}
|
|
else if (MsV1_0Lm20LogonProfile == *((ULONG*) pProfile))
|
|
{
|
|
MSV1_0_LM20_LOGON_PROFILE* pMsvLm20LogonProfile = (MSV1_0_LM20_LOGON_PROFILE*) pProfile;
|
|
DebugPrintf(Level, "MsV1_0Lm20LogonProfile: "
|
|
"UserFlags %#x, LogonDomainName %wZ, LogonServer %wZ, UserParameters %#x\n",
|
|
pMsvLm20LogonProfile->UserFlags,
|
|
&pMsvLm20LogonProfile->LogonDomainName,
|
|
&pMsvLm20LogonProfile->LogonServer,
|
|
pMsvLm20LogonProfile->UserParameters);
|
|
DebugPrintHex(Level, "UserSessionKey:", MSV1_0_USER_SESSION_KEY_LENGTH, pMsvLm20LogonProfile->UserSessionKey);
|
|
DebugPrintHex(Level, "LanmanSessionKey:", MSV1_0_LANMAN_SESSION_KEY_LENGTH, pMsvLm20LogonProfile->LanmanSessionKey);
|
|
DebugPrintSysTimeAsLocalTime(Level, "KickOffTime", &pMsvLm20LogonProfile->KickOffTime);
|
|
DebugPrintSysTimeAsLocalTime(Level, "LogoffTime", &pMsvLm20LogonProfile->LogoffTime);
|
|
}
|
|
else if (KerbInteractiveProfile == *((ULONG*) pProfile))
|
|
{
|
|
KERB_TICKET_PROFILE* pKerbTicketProfile = (KERB_TICKET_PROFILE*) pProfile;
|
|
KERB_INTERACTIVE_PROFILE* pKrbInteractiveProfile = &pKerbTicketProfile->Profile;
|
|
DebugPrintf(Level, "KerbInteractiveProfile: "
|
|
"LogCount %#x, BaddPasswordCount %#x, LogonScript %wZ, "
|
|
"HomeDirectory %wZ, FullName %wZ, ProfilePath %wZ, "
|
|
"HomeDriectoryDrive %wZ, LogonServer %wZ, UserFlags %#x\n",
|
|
pKrbInteractiveProfile->LogonCount,
|
|
pKrbInteractiveProfile->BadPasswordCount,
|
|
&pKrbInteractiveProfile->LogonScript,
|
|
&pKrbInteractiveProfile->HomeDirectory,
|
|
&pKrbInteractiveProfile->FullName,
|
|
&pKrbInteractiveProfile->ProfilePath,
|
|
&pKrbInteractiveProfile->HomeDirectoryDrive,
|
|
&pKrbInteractiveProfile->LogonServer,
|
|
pKrbInteractiveProfile->UserFlags);
|
|
DebugPrintSysTimeAsLocalTime(Level, "LogonTime", &pKrbInteractiveProfile->LogonTime);
|
|
DebugPrintSysTimeAsLocalTime(Level, "LogoffTime", &pKrbInteractiveProfile->LogoffTime);
|
|
DebugPrintSysTimeAsLocalTime(Level, "KickOffTime", &pKrbInteractiveProfile->KickOffTime);
|
|
DebugPrintSysTimeAsLocalTime(Level, "PasswordLastSet", &pKrbInteractiveProfile->PasswordLastSet);
|
|
DebugPrintSysTimeAsLocalTime(Level, "PasswordCanChange", &pKrbInteractiveProfile->PasswordCanChange);
|
|
DebugPrintSysTimeAsLocalTime(Level, "PasswordMustChange", &pKrbInteractiveProfile->PasswordMustChange);
|
|
DebugPrintHex(Level, "SessionKey:", sizeof(pKerbTicketProfile->SessionKey), &pKerbTicketProfile->SessionKey);
|
|
}
|
|
else
|
|
{
|
|
DebugPrintf(SSPI_ERROR, "Unsupported profile type %#x\n", *((ULONG*) pProfile));
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
GetLm20LogonInfoNtlmv1(
|
|
IN UNICODE_STRING* pUserName,
|
|
IN UNICODE_STRING* pDomainName,
|
|
IN UNICODE_STRING* pPassword,
|
|
IN UNICODE_STRING* pWorkstation,
|
|
IN UCHAR ChallengeToClient[MSV1_0_CHALLENGE_LENGTH],
|
|
OUT ULONG* pcbLogonInfo,
|
|
OUT PMSV1_0_LM20_LOGON *ppLognInfo
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
|
|
PMSV1_0_LM20_LOGON pMsvNetAuthInfo = NULL;
|
|
ULONG cbMsvNetAuthInfo;
|
|
|
|
NT_OWF_PASSWORD PasswordHash;
|
|
OEM_STRING LmPassword;
|
|
UCHAR LmPasswordBuf[ LM20_PWLEN + 1 ];
|
|
LM_OWF_PASSWORD LmPasswordHash;
|
|
|
|
DebugPrintf(SSPI_LOG, "GetLm20LogonInfoNtlmv1 UserName %wZ, DomainName %wZ, Password %wZ, Workstation %wZ\n",
|
|
pUserName, pDomainName, pPassword, pWorkstation);
|
|
|
|
*ppLognInfo = NULL;
|
|
*pcbLogonInfo = 0;
|
|
|
|
cbMsvNetAuthInfo = ROUND_UP_COUNT(sizeof(MSV1_0_LM20_LOGON), sizeof(ULONG_PTR))
|
|
+ pUserName->Length
|
|
+ pDomainName->Length
|
|
+ pWorkstation->Length
|
|
+ NT_RESPONSE_LENGTH
|
|
+ LM_RESPONSE_LENGTH;
|
|
|
|
pMsvNetAuthInfo = (PMSV1_0_LM20_LOGON) new CHAR[cbMsvNetAuthInfo];
|
|
|
|
Status DBGCHK = pMsvNetAuthInfo ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Start packing in the string
|
|
//
|
|
|
|
RtlZeroMemory(pMsvNetAuthInfo, cbMsvNetAuthInfo);
|
|
|
|
pMsvNetAuthInfo->MessageType = MsV1_0NetworkLogon; // if set MsV1_0Lm20Logon, ignore ParameterControl
|
|
|
|
//
|
|
// Copy the user name into the authentication buffer
|
|
//
|
|
|
|
pMsvNetAuthInfo->UserName.Length = pUserName->Length;
|
|
pMsvNetAuthInfo->UserName.MaximumLength = pMsvNetAuthInfo->UserName.Length;
|
|
|
|
pMsvNetAuthInfo->UserName.Buffer = (PWSTR)(pMsvNetAuthInfo + 1); // could be aligned here
|
|
RtlCopyMemory(
|
|
pMsvNetAuthInfo->UserName.Buffer,
|
|
pUserName->Buffer,
|
|
pUserName->Length
|
|
);
|
|
|
|
//
|
|
// Copy the domain name into the authentication buffer
|
|
//
|
|
|
|
pMsvNetAuthInfo->LogonDomainName.Length = pDomainName->Length;
|
|
pMsvNetAuthInfo->LogonDomainName.MaximumLength = pDomainName->Length ;
|
|
|
|
pMsvNetAuthInfo->LogonDomainName.Buffer = (PWSTR) ((PBYTE)(pMsvNetAuthInfo->UserName.Buffer)
|
|
+ pMsvNetAuthInfo->UserName.MaximumLength);
|
|
|
|
RtlCopyMemory(
|
|
pMsvNetAuthInfo->LogonDomainName.Buffer,
|
|
pDomainName->Buffer,
|
|
pDomainName->Length
|
|
);
|
|
|
|
//
|
|
// Copy the workstation name into the buffer
|
|
//
|
|
|
|
pMsvNetAuthInfo->Workstation.Length = pWorkstation->Length;
|
|
|
|
pMsvNetAuthInfo->Workstation.MaximumLength = pMsvNetAuthInfo->Workstation.Length;
|
|
|
|
pMsvNetAuthInfo->Workstation.Buffer = (PWSTR) ((PBYTE) (pMsvNetAuthInfo->LogonDomainName.Buffer)
|
|
+ pMsvNetAuthInfo->LogonDomainName.MaximumLength);
|
|
|
|
RtlCopyMemory(
|
|
pMsvNetAuthInfo->Workstation.Buffer,
|
|
pWorkstation->Buffer,
|
|
pWorkstation->Length
|
|
);
|
|
|
|
RtlCopyMemory(pMsvNetAuthInfo->ChallengeToClient,
|
|
ChallengeToClient,
|
|
MSV1_0_CHALLENGE_LENGTH);
|
|
|
|
//
|
|
// Set up space for response
|
|
//
|
|
|
|
pMsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer =
|
|
(((PCHAR) pMsvNetAuthInfo->Workstation.Buffer)
|
|
+ pMsvNetAuthInfo->Workstation.MaximumLength);
|
|
|
|
pMsvNetAuthInfo->CaseSensitiveChallengeResponse.Length = NT_RESPONSE_LENGTH;
|
|
|
|
pMsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength = NT_RESPONSE_LENGTH;
|
|
|
|
RtlCalculateNtOwfPassword(
|
|
pPassword,
|
|
&PasswordHash
|
|
);
|
|
|
|
RtlCalculateNtResponse(
|
|
(PNT_CHALLENGE) ChallengeToClient,
|
|
&PasswordHash,
|
|
(PNT_RESPONSE) pMsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer
|
|
);
|
|
|
|
//
|
|
// Now do the painful LM compatible hash, so anyone who is maintaining
|
|
// their account from a WfW machine will still have a password.
|
|
//
|
|
|
|
LmPassword.Buffer = (PCHAR) LmPasswordBuf;
|
|
LmPassword.Length = LmPassword.MaximumLength = LM20_PWLEN + 1;
|
|
|
|
Status DBGCHK = RtlUpcaseUnicodeStringToOemString(
|
|
&LmPassword,
|
|
pPassword,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
pMsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer =
|
|
((PCHAR) (pMsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer)
|
|
+ pMsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength);
|
|
|
|
pMsvNetAuthInfo->CaseInsensitiveChallengeResponse.Length = LM_RESPONSE_LENGTH;
|
|
pMsvNetAuthInfo->CaseInsensitiveChallengeResponse.MaximumLength = LM_RESPONSE_LENGTH;
|
|
|
|
RtlCalculateLmOwfPassword(
|
|
LmPassword.Buffer,
|
|
&LmPasswordHash
|
|
);
|
|
|
|
RtlZeroMemory(LmPassword.Buffer, LmPassword.Length);
|
|
|
|
RtlCalculateLmResponse(
|
|
(PLM_CHALLENGE) ChallengeToClient,
|
|
&LmPasswordHash,
|
|
(PLM_RESPONSE) pMsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer
|
|
);
|
|
|
|
*ppLognInfo = pMsvNetAuthInfo;
|
|
pMsvNetAuthInfo = NULL;
|
|
*pcbLogonInfo = cbMsvNetAuthInfo;
|
|
|
|
}
|
|
|
|
if (pMsvNetAuthInfo)
|
|
{
|
|
delete [] pMsvNetAuthInfo;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
CalculateNtlmv2Owf(
|
|
IN NT_OWF_PASSWORD* pNtOwfPassword,
|
|
IN UNICODE_STRING* pUserName,
|
|
IN UNICODE_STRING* pLogonDomainName,
|
|
OUT UCHAR Ntlmv2Owf[MSV1_0_NTLM3_OWF_LENGTH]
|
|
)
|
|
{
|
|
HMACMD5_CTX HMACMD5Context;
|
|
|
|
//
|
|
// reserve a scratch buffer
|
|
//
|
|
|
|
WCHAR szUserName[(UNLEN + 4)] = {0};
|
|
UNICODE_STRING UserName = {0, sizeof(szUserName), szUserName};
|
|
|
|
//
|
|
// first make a copy then upcase it
|
|
//
|
|
|
|
UserName.Length = min(UserName.MaximumLength, pUserName->Length);
|
|
|
|
ASSERT(UserName.Length == pUserName->Length);
|
|
|
|
RtlCopyMemory(UserName.Buffer, pUserName->Buffer, UserName.Length);
|
|
|
|
RtlUpcaseUnicodeString(&UserName, &UserName, FALSE);
|
|
|
|
//
|
|
// Calculate Ntlmv2 OWF -- HMAC(MD4(P), (UserName, LogonDomainName))
|
|
//
|
|
|
|
HMACMD5Init(
|
|
&HMACMD5Context,
|
|
(UCHAR *) pNtOwfPassword,
|
|
sizeof(*pNtOwfPassword)
|
|
);
|
|
|
|
HMACMD5Update(
|
|
&HMACMD5Context,
|
|
(UCHAR *) UserName.Buffer,
|
|
UserName.Length
|
|
);
|
|
|
|
HMACMD5Update(
|
|
&HMACMD5Context,
|
|
(UCHAR *) pLogonDomainName->Buffer,
|
|
pLogonDomainName->Length
|
|
);
|
|
|
|
HMACMD5Final(
|
|
&HMACMD5Context,
|
|
Ntlmv2Owf
|
|
);
|
|
}
|
|
|
|
VOID
|
|
GetLmv2Response(
|
|
IN NT_OWF_PASSWORD* pNtOwfPassword,
|
|
IN UNICODE_STRING* pUserName,
|
|
IN UNICODE_STRING* pLogonDomainName,
|
|
IN UCHAR ChallengeToClient[MSV1_0_CHALLENGE_LENGTH],
|
|
IN UCHAR ChallengeFromClient[MSV1_0_CHALLENGE_LENGTH],
|
|
OUT UCHAR Response[MSV1_0_NTLM3_RESPONSE_LENGTH],
|
|
OUT OPTIONAL USER_SESSION_KEY* pUserSessionKey,
|
|
OUT OPTIONAL LM_SESSION_KEY* pLanmanSessionKey // [MSV1_0_LANMAN_SESSION_KEY_LENGTH]
|
|
)
|
|
{
|
|
HMACMD5_CTX HMACMD5Context;
|
|
UCHAR Ntlmv2Owf[MSV1_0_NTLM3_OWF_LENGTH];
|
|
|
|
C_ASSERT(MD5DIGESTLEN == MSV1_0_NTLM3_RESPONSE_LENGTH);
|
|
|
|
//
|
|
// get Ntlmv2 OWF
|
|
//
|
|
|
|
CalculateNtlmv2Owf(
|
|
pNtOwfPassword,
|
|
pUserName,
|
|
pLogonDomainName,
|
|
Ntlmv2Owf
|
|
);
|
|
|
|
//
|
|
// Calculate Ntlmv2 Response
|
|
// HMAC(Ntlmv2Owf, (ChallengeToClient, ChallengeFromClient))
|
|
//
|
|
|
|
HMACMD5Init(
|
|
&HMACMD5Context,
|
|
Ntlmv2Owf,
|
|
MSV1_0_NTLM3_OWF_LENGTH
|
|
);
|
|
|
|
HMACMD5Update(
|
|
&HMACMD5Context,
|
|
ChallengeToClient,
|
|
MSV1_0_CHALLENGE_LENGTH
|
|
);
|
|
|
|
HMACMD5Update(
|
|
&HMACMD5Context,
|
|
ChallengeFromClient,
|
|
MSV1_0_CHALLENGE_LENGTH
|
|
);
|
|
|
|
HMACMD5Final(
|
|
&HMACMD5Context,
|
|
Response
|
|
);
|
|
|
|
if (pUserSessionKey && pLanmanSessionKey)
|
|
{
|
|
// now compute the session keys
|
|
// HMAC(Kr, R)
|
|
HMACMD5Init(
|
|
&HMACMD5Context,
|
|
Ntlmv2Owf,
|
|
MSV1_0_NTLM3_OWF_LENGTH
|
|
);
|
|
|
|
HMACMD5Update(
|
|
&HMACMD5Context,
|
|
Response,
|
|
MSV1_0_NTLM3_RESPONSE_LENGTH
|
|
);
|
|
|
|
ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
|
|
HMACMD5Final(
|
|
&HMACMD5Context,
|
|
(PUCHAR)pUserSessionKey
|
|
);
|
|
|
|
ASSERT(MSV1_0_LANMAN_SESSION_KEY_LENGTH <= MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
RtlCopyMemory(
|
|
pLanmanSessionKey,
|
|
pUserSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH
|
|
);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
Lm20GetNtlmv2Response(
|
|
IN NT_OWF_PASSWORD* pNtOwfPassword,
|
|
IN UNICODE_STRING* pUserName,
|
|
IN UNICODE_STRING* pLogonDomainName,
|
|
IN STRING* pTargetInfo,
|
|
IN UCHAR ChallengeToClient[MSV1_0_CHALLENGE_LENGTH],
|
|
OUT MSV1_0_NTLM3_RESPONSE* pNtlmv2Response,
|
|
OUT MSV1_0_LM3_RESPONSE* pLmv2Response,
|
|
OUT USER_SESSION_KEY* pNtUserSessionKey,
|
|
OUT LM_SESSION_KEY* pLmSessionKey
|
|
)
|
|
{
|
|
//
|
|
// fill in version numbers, timestamp, and client's challenge
|
|
//
|
|
|
|
pNtlmv2Response->RespType = 1;
|
|
pNtlmv2Response->HiRespType = 1;
|
|
pNtlmv2Response->Flags = 0;
|
|
pNtlmv2Response->MsgWord = 0;
|
|
|
|
GetSystemTimeAsFileTime((FILETIME*)(&pNtlmv2Response->TimeStamp));
|
|
|
|
RtlGenRandom(pNtlmv2Response->ChallengeFromClient, MSV1_0_CHALLENGE_LENGTH);
|
|
|
|
RtlCopyMemory(pNtlmv2Response->Buffer, pTargetInfo->Buffer, pTargetInfo->Length);
|
|
|
|
//
|
|
// Calculate Ntlmv2 response, filling in response field
|
|
//
|
|
|
|
GetNtlmv2Response(
|
|
pNtOwfPassword,
|
|
pUserName,
|
|
pLogonDomainName,
|
|
pTargetInfo->Length,
|
|
ChallengeToClient,
|
|
pNtlmv2Response,
|
|
pNtUserSessionKey,
|
|
pLmSessionKey
|
|
);
|
|
|
|
//
|
|
// Use same challenge to compute the LMV2 response
|
|
//
|
|
|
|
RtlCopyMemory(pLmv2Response->ChallengeFromClient, pNtlmv2Response->ChallengeFromClient, MSV1_0_CHALLENGE_LENGTH);
|
|
|
|
//
|
|
// Calculate LMV2 response
|
|
//
|
|
|
|
GetLmv2Response(
|
|
pNtOwfPassword,
|
|
pUserName,
|
|
pLogonDomainName,
|
|
ChallengeToClient,
|
|
pLmv2Response->ChallengeFromClient,
|
|
pLmv2Response->Response,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
VOID
|
|
GetNtlmv2Response(
|
|
IN NT_OWF_PASSWORD* pNtOwfPassword,
|
|
IN UNICODE_STRING* pUserName,
|
|
IN UNICODE_STRING* pLogonDomainName,
|
|
IN ULONG TargetInfoLength,
|
|
IN UCHAR ChallengeToClient[MSV1_0_CHALLENGE_LENGTH],
|
|
IN OUT MSV1_0_NTLM3_RESPONSE* pNtlmv2Response,
|
|
OUT USER_SESSION_KEY* pNtUserSessionKey,
|
|
OUT LM_SESSION_KEY* pLmSessionKey
|
|
)
|
|
{
|
|
HMACMD5_CTX HMACMD5Context;
|
|
UCHAR Ntlmv2Owf[MSV1_0_NTLM3_OWF_LENGTH];
|
|
|
|
C_ASSERT(MD5DIGESTLEN == MSV1_0_NTLM3_RESPONSE_LENGTH);
|
|
C_ASSERT(MD5DIGESTLEN == sizeof(USER_SESSION_KEY));
|
|
C_ASSERT(sizeof(LM_SESSION_KEY) <= sizeof(USER_SESSION_KEY));
|
|
|
|
//
|
|
// get Ntlmv2 OWF
|
|
//
|
|
|
|
CalculateNtlmv2Owf(
|
|
pNtOwfPassword,
|
|
pUserName,
|
|
pLogonDomainName,
|
|
Ntlmv2Owf
|
|
);
|
|
|
|
HMACMD5Init(
|
|
&HMACMD5Context,
|
|
Ntlmv2Owf,
|
|
MSV1_0_NTLM3_OWF_LENGTH
|
|
);
|
|
|
|
HMACMD5Update(
|
|
&HMACMD5Context,
|
|
ChallengeToClient,
|
|
MSV1_0_CHALLENGE_LENGTH
|
|
);
|
|
|
|
HMACMD5Update(
|
|
&HMACMD5Context,
|
|
&pNtlmv2Response->RespType,
|
|
(MSV1_0_NTLM3_INPUT_LENGTH + TargetInfoLength)
|
|
);
|
|
|
|
HMACMD5Final(
|
|
&HMACMD5Context,
|
|
pNtlmv2Response->Response
|
|
);
|
|
|
|
//
|
|
// now compute the session keys
|
|
// HMAC(Kr, R)
|
|
//
|
|
|
|
HMACMD5Init(
|
|
&HMACMD5Context,
|
|
Ntlmv2Owf,
|
|
MSV1_0_NTLM3_OWF_LENGTH
|
|
);
|
|
|
|
HMACMD5Update(
|
|
&HMACMD5Context,
|
|
pNtlmv2Response->Response,
|
|
MSV1_0_NTLM3_RESPONSE_LENGTH
|
|
);
|
|
|
|
HMACMD5Final(
|
|
&HMACMD5Context,
|
|
(UCHAR*) pNtUserSessionKey
|
|
);
|
|
|
|
RtlCopyMemory(pLmSessionKey, pNtUserSessionKey, sizeof(LM_SESSION_KEY));
|
|
}
|
|
|
|
NTSTATUS
|
|
GetLm20LogonInfoNtlmv2(
|
|
IN UNICODE_STRING* pUserName,
|
|
IN UNICODE_STRING* pDomainName,
|
|
IN UNICODE_STRING* pPassword,
|
|
IN UNICODE_STRING* pWorkstation,
|
|
IN OPTIONAL UNICODE_STRING* pTargetName,
|
|
IN OPTIONAL STRING* pTargetInfo,
|
|
IN UCHAR ChallengeToClient[MSV1_0_CHALLENGE_LENGTH],
|
|
OUT ULONG* pcbLogonInfo,
|
|
OUT PMSV1_0_LM20_LOGON *ppLognInfo
|
|
)
|
|
{
|
|
TNtStatus Status = STATUS_SUCCESS;
|
|
|
|
STRING TargetInfo = {0};
|
|
|
|
PMSV1_0_LM20_LOGON pMsvNetAuthInfo = NULL;
|
|
ULONG cbMsvNetAuthInfo = 0;
|
|
NT_OWF_PASSWORD NtOwfPassword;
|
|
USER_SESSION_KEY NtUserSessionKey;
|
|
LM_SESSION_KEY LmSessionKey;
|
|
MSV1_0_LM3_RESPONSE Lmv2Response;
|
|
MSV1_0_NTLM3_RESPONSE* pNtlmv2Reponse = NULL;
|
|
ULONG cbNtlmv2Response = 0;
|
|
|
|
DebugPrintf(SSPI_LOG, "GetLm20LogonInfoNtlmv2 UserName %wZ, DomainName %wZ, Password %wZ, Workstation %wZ\n",
|
|
pUserName, pDomainName, pPassword, pWorkstation);
|
|
|
|
*ppLognInfo = NULL;
|
|
*pcbLogonInfo = 0;
|
|
|
|
RtlCalculateNtOwfPassword(
|
|
pPassword,
|
|
&NtOwfPassword
|
|
);
|
|
|
|
if (pTargetInfo)
|
|
{
|
|
TargetInfo = *pTargetInfo;
|
|
}
|
|
else if (pTargetName)
|
|
{
|
|
Status DBGCHK = CreateTargetInfo(pTargetName, &TargetInfo);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
cbNtlmv2Response = ROUND_UP_COUNT(sizeof(MSV1_0_NTLM3_RESPONSE), sizeof(ULONG_PTR)) + TargetInfo.Length;
|
|
pNtlmv2Reponse = (MSV1_0_NTLM3_RESPONSE*) new CHAR[cbNtlmv2Response];
|
|
Status DBGCHK = pNtlmv2Reponse ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Lm20GetNtlmv2Response(
|
|
&NtOwfPassword,
|
|
pUserName,
|
|
pDomainName,
|
|
&TargetInfo,
|
|
ChallengeToClient,
|
|
pNtlmv2Reponse,
|
|
&Lmv2Response,
|
|
&NtUserSessionKey,
|
|
&LmSessionKey
|
|
);
|
|
cbMsvNetAuthInfo = ROUND_UP_COUNT(sizeof(MSV1_0_LM20_LOGON), sizeof(ULONG_PTR))
|
|
+ pUserName->Length
|
|
+ pDomainName->Length
|
|
+ pWorkstation->Length
|
|
+ cbNtlmv2Response
|
|
+ sizeof(Lmv2Response);
|
|
|
|
pMsvNetAuthInfo = (PMSV1_0_LM20_LOGON) new CHAR[cbMsvNetAuthInfo];
|
|
|
|
Status DBGCHK = pMsvNetAuthInfo ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Start packing in the string
|
|
//
|
|
|
|
RtlZeroMemory(pMsvNetAuthInfo, cbMsvNetAuthInfo);
|
|
|
|
pMsvNetAuthInfo->MessageType = MsV1_0NetworkLogon;
|
|
|
|
//
|
|
// Copy the user name into the authentication buffer
|
|
//
|
|
|
|
pMsvNetAuthInfo->UserName.Length = pUserName->Length;
|
|
pMsvNetAuthInfo->UserName.MaximumLength = pMsvNetAuthInfo->UserName.Length;
|
|
|
|
pMsvNetAuthInfo->UserName.Buffer = (PWSTR) (pMsvNetAuthInfo + 1); // could be aligned here
|
|
RtlCopyMemory(
|
|
pMsvNetAuthInfo->UserName.Buffer,
|
|
pUserName->Buffer,
|
|
pUserName->Length
|
|
);
|
|
|
|
//
|
|
// Copy the domain name into the authentication buffer
|
|
//
|
|
|
|
pMsvNetAuthInfo->LogonDomainName.Length = pDomainName->Length;
|
|
pMsvNetAuthInfo->LogonDomainName.MaximumLength = pDomainName->Length ;
|
|
|
|
pMsvNetAuthInfo->LogonDomainName.Buffer = (PWSTR) ((PBYTE)(pMsvNetAuthInfo->UserName.Buffer)
|
|
+ pMsvNetAuthInfo->UserName.MaximumLength);
|
|
|
|
RtlCopyMemory(
|
|
pMsvNetAuthInfo->LogonDomainName.Buffer,
|
|
pDomainName->Buffer,
|
|
pDomainName->Length
|
|
);
|
|
|
|
//
|
|
// Copy the workstation name into the buffer
|
|
//
|
|
|
|
pMsvNetAuthInfo->Workstation.Length = pWorkstation->Length;
|
|
|
|
pMsvNetAuthInfo->Workstation.MaximumLength = pMsvNetAuthInfo->Workstation.Length;
|
|
|
|
pMsvNetAuthInfo->Workstation.Buffer = (PWSTR) ((PBYTE) (pMsvNetAuthInfo->LogonDomainName.Buffer)
|
|
+ pMsvNetAuthInfo->LogonDomainName.MaximumLength );
|
|
|
|
RtlCopyMemory(
|
|
pMsvNetAuthInfo->Workstation.Buffer,
|
|
pWorkstation->Buffer,
|
|
pWorkstation->Length
|
|
);
|
|
|
|
RtlCopyMemory(pMsvNetAuthInfo->ChallengeToClient,
|
|
ChallengeToClient,
|
|
MSV1_0_CHALLENGE_LENGTH);
|
|
|
|
//
|
|
// Set up space for response
|
|
//
|
|
|
|
pMsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer =
|
|
((PCHAR) (pMsvNetAuthInfo->Workstation.Buffer)
|
|
+ pMsvNetAuthInfo->Workstation.MaximumLength);
|
|
|
|
pMsvNetAuthInfo->CaseSensitiveChallengeResponse.Length = (USHORT) cbNtlmv2Response;
|
|
|
|
pMsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength = (USHORT) cbNtlmv2Response;
|
|
|
|
RtlCopyMemory(
|
|
pMsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer,
|
|
pNtlmv2Reponse,
|
|
cbNtlmv2Response
|
|
);
|
|
|
|
pMsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer =
|
|
((PCHAR) (pMsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer)
|
|
+ pMsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength );
|
|
|
|
pMsvNetAuthInfo->CaseInsensitiveChallengeResponse.Length = sizeof(Lmv2Response);
|
|
|
|
pMsvNetAuthInfo->CaseInsensitiveChallengeResponse.MaximumLength = sizeof(Lmv2Response);
|
|
|
|
RtlCopyMemory(
|
|
pMsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer,
|
|
&Lmv2Response,
|
|
sizeof(Lmv2Response)
|
|
);
|
|
|
|
*ppLognInfo = pMsvNetAuthInfo;
|
|
pMsvNetAuthInfo = NULL;
|
|
*pcbLogonInfo = cbMsvNetAuthInfo;
|
|
|
|
}
|
|
|
|
if (pMsvNetAuthInfo)
|
|
{
|
|
delete [] pMsvNetAuthInfo;
|
|
}
|
|
|
|
if (pNtlmv2Reponse)
|
|
{
|
|
delete [] pNtlmv2Reponse;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetMsvInteractiveLogonInfo(
|
|
IN UNICODE_STRING* pUserName,
|
|
IN UNICODE_STRING* pLogonDomainName,
|
|
IN UNICODE_STRING* pPassword,
|
|
OUT ULONG* pcbLogonInfo,
|
|
OUT MSV1_0_INTERACTIVE_LOGON** ppLogonInfo
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
ULONG cbLogonInfo = 0;
|
|
|
|
UCHAR* pWhere = NULL;
|
|
MSV1_0_INTERACTIVE_LOGON* pLogonInfo = NULL;
|
|
|
|
DebugPrintf(SSPI_LOG, "GetMsvInteractiveLogonInfo UserName %wZ, LogonDomainName %wZ, Password %wZ\n",
|
|
pUserName, pLogonDomainName, pPassword);
|
|
cbLogonInfo = ROUND_UP_COUNT(sizeof(MSV1_0_INTERACTIVE_LOGON), sizeof(ULONG_PTR))
|
|
+ pUserName->Length
|
|
+ pLogonDomainName->Length
|
|
+ pPassword->Length;
|
|
|
|
pLogonInfo = (MSV1_0_INTERACTIVE_LOGON*) new CHAR[cbLogonInfo];
|
|
|
|
Status DBGCHK = pLogonInfo ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
pLogonInfo->MessageType = MsV1_0InteractiveLogon;
|
|
|
|
pWhere = (PUCHAR) (pLogonInfo + 1);
|
|
|
|
pLogonInfo->UserName.Buffer = (PWSTR) pWhere;
|
|
pLogonInfo->UserName.MaximumLength = pUserName->Length;
|
|
pLogonInfo->UserName.Length = pUserName->Length;
|
|
|
|
RtlCopyMemory(pLogonInfo->UserName.Buffer,
|
|
pUserName->Buffer,
|
|
pUserName->Length);
|
|
|
|
pWhere += pLogonInfo->UserName.Length;
|
|
|
|
pLogonInfo->LogonDomainName.Buffer = (PWSTR) pWhere;
|
|
pLogonInfo->LogonDomainName.MaximumLength = pLogonDomainName->Length;
|
|
pLogonInfo->LogonDomainName.Length = pLogonDomainName->Length;
|
|
|
|
RtlCopyMemory(pLogonInfo->LogonDomainName.Buffer,
|
|
pLogonDomainName->Buffer,
|
|
pLogonDomainName->Length);
|
|
|
|
pWhere += pLogonInfo->LogonDomainName.Length;
|
|
|
|
pLogonInfo->Password.Buffer = (PWSTR) pWhere;
|
|
pLogonInfo->Password.MaximumLength = pPassword->Length;
|
|
pLogonInfo->Password.Length = pPassword->Length;
|
|
|
|
RtlCopyMemory(pLogonInfo->Password.Buffer,
|
|
pPassword->Buffer,
|
|
pPassword->Length);
|
|
|
|
pWhere += pLogonInfo->Password.Length;
|
|
|
|
*ppLogonInfo = pLogonInfo;
|
|
pLogonInfo = NULL;
|
|
*pcbLogonInfo = cbLogonInfo;
|
|
}
|
|
|
|
if (pLogonInfo)
|
|
{
|
|
delete [] pLogonInfo;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetKrbS4U2SelfLogonInfo(
|
|
IN UNICODE_STRING* pClientUpn,
|
|
IN OPTIONAL UNICODE_STRING* pClientRealm,
|
|
IN ULONG Flags,
|
|
OUT ULONG* pcbLogonInfo,
|
|
OUT KERB_S4U_LOGON** ppLogonInfo
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
ULONG cbLogonInfo = 0;
|
|
|
|
WCHAR* pWhere = NULL;
|
|
KERB_S4U_LOGON* pLogonInfo = NULL;
|
|
|
|
DebugPrintf(SSPI_LOG, "GetKrbS4U2SelfLogonInfo ClientUpn %wZ, ClientRealm %wZ, Flags %#x\n",
|
|
pClientUpn, pClientRealm, Flags);
|
|
|
|
cbLogonInfo = ROUND_UP_COUNT(sizeof(KERB_S4U_LOGON), sizeof(ULONG_PTR))
|
|
+ pClientUpn->Length + sizeof(WCHAR)
|
|
+ (pClientRealm ? pClientRealm->Length : 0) + sizeof(WCHAR);
|
|
pLogonInfo = (KERB_S4U_LOGON*) new CHAR[cbLogonInfo];
|
|
|
|
Status DBGCHK = pLogonInfo ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
RtlZeroMemory(pLogonInfo, cbLogonInfo);
|
|
|
|
pLogonInfo->MessageType = KerbS4ULogon;
|
|
|
|
pWhere = (PWCHAR) (pLogonInfo + 1);
|
|
|
|
PackUnicodeStringAsUnicodeStringZ(pClientUpn, &pWhere, &pLogonInfo->ClientUpn);
|
|
|
|
if (pClientRealm)
|
|
{
|
|
PackUnicodeStringAsUnicodeStringZ(pClientRealm, &pWhere, &pLogonInfo->ClientRealm);
|
|
}
|
|
|
|
pLogonInfo->Flags = Flags;
|
|
|
|
*ppLogonInfo = pLogonInfo;
|
|
pLogonInfo = NULL;
|
|
*pcbLogonInfo = cbLogonInfo;
|
|
}
|
|
|
|
if (pLogonInfo)
|
|
{
|
|
delete [] pLogonInfo;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetKrbInteractiveLogonInfo(
|
|
IN UNICODE_STRING* pUserName,
|
|
IN UNICODE_STRING* pLogonDomainName,
|
|
IN UNICODE_STRING* pPassword,
|
|
OUT ULONG* pcbLogonInfo,
|
|
OUT KERB_INTERACTIVE_LOGON** ppLogonInfo
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
ULONG cbLogonInfo = 0;
|
|
|
|
UCHAR* pWhere = NULL;
|
|
KERB_INTERACTIVE_LOGON* pLogonInfo = NULL;
|
|
|
|
DebugPrintf(SSPI_LOG, "GetKrbInteractiveLogonInfo UserName %wZ, LogonDomainName %wZ, Password %wZ\n",
|
|
pUserName, pLogonDomainName, pPassword);
|
|
|
|
cbLogonInfo = ROUND_UP_COUNT(sizeof(KERB_INTERACTIVE_LOGON), sizeof(ULONG_PTR))
|
|
+ pUserName->Length
|
|
+ pLogonDomainName->Length
|
|
+ pPassword->Length;
|
|
|
|
pLogonInfo = (KERB_INTERACTIVE_LOGON*) new CHAR[cbLogonInfo];
|
|
|
|
Status DBGCHK = pLogonInfo ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
pLogonInfo->MessageType = KerbInteractiveLogon;
|
|
|
|
pWhere = (PUCHAR) (pLogonInfo + 1);
|
|
|
|
pLogonInfo->UserName.Buffer = (PWSTR) pWhere;
|
|
pLogonInfo->UserName.MaximumLength = pUserName->Length;
|
|
pLogonInfo->UserName.Length = pUserName->Length;
|
|
|
|
RtlCopyMemory(pLogonInfo->UserName.Buffer,
|
|
pUserName->Buffer,
|
|
pUserName->Length);
|
|
|
|
pWhere += pLogonInfo->UserName.Length;
|
|
|
|
pLogonInfo->LogonDomainName.Buffer = (PWSTR) pWhere;
|
|
pLogonInfo->LogonDomainName.MaximumLength = pLogonDomainName->Length;
|
|
pLogonInfo->LogonDomainName.Length = pLogonDomainName->Length;
|
|
|
|
RtlCopyMemory(pLogonInfo->LogonDomainName.Buffer,
|
|
pLogonDomainName->Buffer,
|
|
pLogonDomainName->Length);
|
|
|
|
pWhere += pLogonInfo->LogonDomainName.Length;
|
|
|
|
pLogonInfo->Password.Buffer = (PWSTR) pWhere;
|
|
pLogonInfo->Password.MaximumLength = pPassword->Length;
|
|
pLogonInfo->Password.Length = pPassword->Length;
|
|
|
|
RtlCopyMemory(pLogonInfo->Password.Buffer,
|
|
pPassword->Buffer,
|
|
pPassword->Length);
|
|
|
|
pWhere += pLogonInfo->Password.Length;
|
|
|
|
*ppLogonInfo = pLogonInfo;
|
|
pLogonInfo = NULL;
|
|
*pcbLogonInfo = cbLogonInfo;
|
|
}
|
|
|
|
if (pLogonInfo)
|
|
{
|
|
delete [] pLogonInfo;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
KrbLsaLogonUser(
|
|
IN HANDLE hLsa,
|
|
IN ULONG PackageId,
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN UNICODE_STRING* pUserName,
|
|
IN UNICODE_STRING* pDomainName,
|
|
IN UNICODE_STRING* pPassword,
|
|
IN ULONG Flags,
|
|
OUT HANDLE* phToken
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
NTSTATUS SubStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
PVOID pLogonInfo = NULL;
|
|
ULONG cbLogonInfo = 0;
|
|
|
|
LSA_STRING Name = {0};
|
|
|
|
TOKEN_SOURCE SourceContext = {0};
|
|
KERB_TICKET_PROFILE* pKerbTicketProfile = NULL;
|
|
ULONG cbProfileSize = 0;
|
|
LUID LogonId = {0};
|
|
QUOTA_LIMITS Quotas = {0};
|
|
|
|
DebugPrintf(SSPI_LOG, "KrbLsaLogonUser PackageId %#x, LogonType %#x, "
|
|
"UserName %wZ, DomainName %wZ, Password %wZ\n",
|
|
PackageId, LogonType, pUserName,
|
|
pDomainName, pPassword);
|
|
|
|
switch (LogonType)
|
|
{
|
|
case Network:
|
|
Status DBGCHK = GetKrbS4U2SelfLogonInfo(
|
|
pUserName,
|
|
pDomainName,
|
|
Flags,
|
|
&cbLogonInfo,
|
|
(KERB_S4U_LOGON**) &pLogonInfo
|
|
);
|
|
break;
|
|
|
|
case Interactive:
|
|
case CachedInteractive:
|
|
case RemoteInteractive:
|
|
case Unlock:
|
|
default:
|
|
Status DBGCHK = GetKrbInteractiveLogonInfo(
|
|
pUserName,
|
|
pDomainName,
|
|
pPassword,
|
|
&cbLogonInfo,
|
|
(KERB_INTERACTIVE_LOGON**) &pLogonInfo
|
|
);
|
|
break;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
SspiPrintHex(SSPI_LOG, TEXT("KrbLsaLogonUser LogonInfo"), cbLogonInfo, pLogonInfo);
|
|
|
|
strncpy(
|
|
SourceContext.SourceName,
|
|
"ssptest",
|
|
sizeof(SourceContext.SourceName)
|
|
);
|
|
NtAllocateLocallyUniqueId(&SourceContext.SourceIdentifier);
|
|
|
|
//
|
|
// Now call LsaLogonUser
|
|
//
|
|
|
|
RtlInitString(
|
|
&Name,
|
|
"ssptest"
|
|
);
|
|
|
|
Status DBGCHK = LsaLogonUser(
|
|
hLsa,
|
|
&Name,
|
|
LogonType,
|
|
PackageId,
|
|
pLogonInfo,
|
|
cbLogonInfo,
|
|
NULL, // no token groups
|
|
&SourceContext,
|
|
(VOID**) &pKerbTicketProfile,
|
|
&cbProfileSize,
|
|
&LogonId,
|
|
phToken,
|
|
&Quotas,
|
|
&SubStatus
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status DBGCHK = SubStatus;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DebugPrintf(SSPI_LOG, "LogonId %#x:%#x\n", LogonId.HighPart, LogonId.LowPart);
|
|
DebugPrintf(SSPI_LOG, "TokenHandle %p\n", *phToken);
|
|
DebugPrintProfileAndQuotas(SSPI_LOG, pKerbTicketProfile, &Quotas);
|
|
}
|
|
|
|
if (pKerbTicketProfile)
|
|
{
|
|
LsaFreeReturnBuffer(pKerbTicketProfile);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MsvLsaLogonUser(
|
|
IN HANDLE hLsa,
|
|
IN ULONG PackageId,
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN UNICODE_STRING* pUserName,
|
|
IN UNICODE_STRING* pDomainName,
|
|
IN UNICODE_STRING* pPassword,
|
|
IN UNICODE_STRING* pWorkstation,
|
|
IN ELogonTypeSubType SubType,
|
|
OUT HANDLE* phToken
|
|
)
|
|
{
|
|
TNtStatus Status;
|
|
NTSTATUS SubStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
PVOID pLogonInfo = NULL;
|
|
ULONG cbLogonInfo = 0;
|
|
LSA_STRING Name = {0};
|
|
|
|
TOKEN_SOURCE SourceContext = {0};
|
|
VOID* pProfile = NULL;
|
|
ULONG cbProfileSize = 0;
|
|
LUID LogonId = {0};
|
|
QUOTA_LIMITS Quotas = {0};
|
|
UCHAR ChallengeToClient[MSV1_0_CHALLENGE_LENGTH] = {0};
|
|
|
|
DebugPrintf(SSPI_LOG, "MsvLsaLogonUser PackageId %#x, LogonType %#x, SubType %#x, "
|
|
"UserName %wZ, DomainName %wZ, Password %wZ, Workstation %wZ\n",
|
|
PackageId, LogonType, SubType, pUserName,
|
|
pDomainName, pPassword, pWorkstation);
|
|
|
|
RtlGenRandom(ChallengeToClient, sizeof(ChallengeToClient));
|
|
|
|
switch (LogonType)
|
|
{
|
|
case Network:
|
|
switch (SubType)
|
|
{
|
|
case kNetworkLogonNtlmv1:
|
|
Status DBGCHK = GetLm20LogonInfoNtlmv1(
|
|
pUserName,
|
|
pDomainName,
|
|
pPassword,
|
|
pWorkstation,
|
|
ChallengeToClient,
|
|
&cbLogonInfo,
|
|
(MSV1_0_LM20_LOGON **) &pLogonInfo
|
|
);
|
|
break;
|
|
|
|
case kNetworkLogonNtlmv2:
|
|
Status DBGCHK = GetLm20LogonInfoNtlmv2(
|
|
pUserName,
|
|
pDomainName,
|
|
pPassword,
|
|
pWorkstation,
|
|
NULL, // no target name
|
|
NULL, // no target info
|
|
ChallengeToClient,
|
|
&cbLogonInfo,
|
|
(MSV1_0_LM20_LOGON **) &pLogonInfo
|
|
);
|
|
break;
|
|
|
|
case kSubAuthLogon:
|
|
default:
|
|
Status DBGCHK = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case Interactive:
|
|
case CachedInteractive:
|
|
case RemoteInteractive:
|
|
case Unlock:
|
|
default:
|
|
Status DBGCHK = GetMsvInteractiveLogonInfo(
|
|
pUserName,
|
|
pDomainName,
|
|
pPassword,
|
|
&cbLogonInfo,
|
|
(MSV1_0_INTERACTIVE_LOGON **) &pLogonInfo
|
|
);
|
|
break;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
strncpy(
|
|
SourceContext.SourceName,
|
|
"ssptest",
|
|
sizeof(SourceContext.SourceName)
|
|
);
|
|
NtAllocateLocallyUniqueId(&SourceContext.SourceIdentifier);
|
|
|
|
//
|
|
// Now call LsaLogonUser
|
|
//
|
|
|
|
RtlInitString(
|
|
&Name,
|
|
"ssptest"
|
|
);
|
|
|
|
Status DBGCHK = LsaLogonUser(
|
|
hLsa,
|
|
&Name,
|
|
LogonType,
|
|
PackageId,
|
|
pLogonInfo,
|
|
cbLogonInfo,
|
|
NULL, // no token groups
|
|
&SourceContext,
|
|
(VOID**) &pProfile,
|
|
&cbProfileSize,
|
|
&LogonId,
|
|
phToken,
|
|
&Quotas,
|
|
&SubStatus
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status DBGCHK = SubStatus;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DebugPrintf(SSPI_LOG, "LogonId %#x:%#x\n", LogonId.HighPart, LogonId.LowPart);
|
|
DebugPrintf(SSPI_LOG, "TokenHandle %p\n", *phToken);
|
|
DebugPrintProfileAndQuotas(SSPI_LOG, pProfile, &Quotas);
|
|
}
|
|
|
|
if (pProfile)
|
|
{
|
|
LsaFreeReturnBuffer(pProfile);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|