Leaked source code of windows server 2003
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

/*++
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;
}