windows-nt/Source/XPSP1/NT/ds/security/protocols/kerberos/client2/kerbwow.cxx

1245 lines
38 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 1992 - 1996
//
// File: kerbwow.cxx
//
// Contents: Code for 32-64 bit interop for the Kerberos package
//
//
// History: 25-Oct-2000 JSchwart Created
//
//------------------------------------------------------------------------
#include <kerb.hxx>
#include <kerbp.h>
#ifdef _WIN64
#ifdef DEBUG_SUPPORT
static TCHAR THIS_FILE[]=TEXT(__FILE__);
#endif
#define FILENO FILENO_KERBWOW
//
// WOW versions of public Kerberos logon buffer structures. These MUST
// be kept in sync with their public counterparts!
//
typedef struct _KERB_INTERACTIVE_LOGON_WOW64
{
KERB_LOGON_SUBMIT_TYPE MessageType;
UNICODE_STRING_WOW64 LogonDomainName;
UNICODE_STRING_WOW64 UserName;
UNICODE_STRING_WOW64 Password;
}
KERB_INTERACTIVE_LOGON_WOW64, *PKERB_INTERACTIVE_LOGON_WOW64;
typedef struct _KERB_INTERACTIVE_UNLOCK_LOGON_WOW64
{
KERB_INTERACTIVE_LOGON_WOW64 Logon;
LUID LogonId;
}
KERB_INTERACTIVE_UNLOCK_LOGON_WOW64, *PKERB_INTERACTIVE_UNLOCK_LOGON_WOW64;
typedef struct _KERB_SMART_CARD_LOGON_WOW64
{
KERB_LOGON_SUBMIT_TYPE MessageType;
UNICODE_STRING_WOW64 Pin;
ULONG CspDataLength;
ULONG CspData;
}
KERB_SMART_CARD_LOGON_WOW64, *PKERB_SMART_CARD_LOGON_WOW64;
typedef struct _KERB_SMART_CARD_UNLOCK_LOGON_WOW64
{
KERB_SMART_CARD_LOGON_WOW64 Logon;
LUID LogonId;
}
KERB_SMART_CARD_UNLOCK_LOGON_WOW64, *PKERB_SMART_CARD_UNLOCK_LOGON_WOW64;
typedef struct _KERB_TICKET_LOGON_WOW64
{
KERB_LOGON_SUBMIT_TYPE MessageType;
ULONG Flags;
ULONG ServiceTicketLength;
ULONG TicketGrantingTicketLength;
ULONG ServiceTicket;
ULONG TicketGrantingTicket;
}
KERB_TICKET_LOGON_WOW64, *PKERB_TICKET_LOGON_WOW64;
typedef struct _KERB_TICKET_UNLOCK_LOGON_WOW64
{
KERB_TICKET_LOGON_WOW64 Logon;
LUID LogonId;
}
KERB_TICKET_UNLOCK_LOGON_WOW64, *PKERB_TICKET_UNLOCK_LOGON_WOW64;
//
// WOW versions of public Kerberos profile buffer structures. These MUST
// be kept in sync with their public counterparts!
//
typedef struct _KERB_INTERACTIVE_PROFILE_WOW64
{
KERB_PROFILE_BUFFER_TYPE MessageType;
USHORT LogonCount;
USHORT BadPasswordCount;
LARGE_INTEGER LogonTime;
LARGE_INTEGER LogoffTime;
LARGE_INTEGER KickOffTime;
LARGE_INTEGER PasswordLastSet;
LARGE_INTEGER PasswordCanChange;
LARGE_INTEGER PasswordMustChange;
UNICODE_STRING_WOW64 LogonScript;
UNICODE_STRING_WOW64 HomeDirectory;
UNICODE_STRING_WOW64 FullName;
UNICODE_STRING_WOW64 ProfilePath;
UNICODE_STRING_WOW64 HomeDirectoryDrive;
UNICODE_STRING_WOW64 LogonServer;
ULONG UserFlags;
}
KERB_INTERACTIVE_PROFILE_WOW64, *PKERB_INTERACTIVE_PROFILE_WOW64;
typedef struct _KERB_SMART_CARD_PROFILE_WOW64
{
KERB_INTERACTIVE_PROFILE_WOW64 Profile;
ULONG CertificateSize;
ULONG CertificateData;
}
KERB_SMART_CARD_PROFILE_WOW64, *PKERB_SMART_CARD_PROFILE_WOW64;
typedef struct KERB_CRYPTO_KEY_WOW64
{
LONG KeyType;
ULONG Length;
ULONG Value;
}
KERB_CRYPTO_KEY_WOW64, *PKERB_CRYPTO_KEY_WOW64;
typedef struct _KERB_TICKET_PROFILE_WOW64
{
KERB_INTERACTIVE_PROFILE_WOW64 Profile;
KERB_CRYPTO_KEY_WOW64 SessionKey;
}
KERB_TICKET_PROFILE_WOW64, *PKERB_TICKET_PROFILE_WOW64;
typedef struct _KERB_INTERNAL_NAME_WOW64
{
SHORT NameType;
USHORT NameCount;
UNICODE_STRING_WOW64 Names[ANYSIZE_ARRAY];
}
KERB_INTERNAL_NAME_WOW64, *PKERB_INTERNAL_NAME_WOW64;
typedef struct _KERB_EXTERNAL_NAME_WOW64
{
SHORT NameType;
USHORT NameCount;
UNICODE_STRING_WOW64 Names[ANYSIZE_ARRAY];
}
KERB_EXTERNAL_NAME_WOW64, *PKERB_EXTERNAL_NAME_WOW64;
typedef struct _KERB_EXTERNAL_TICKET_WOW64
{
ULONG ServiceName;
ULONG TargetName;
ULONG ClientName;
UNICODE_STRING_WOW64 DomainName;
UNICODE_STRING_WOW64 TargetDomainName;
UNICODE_STRING_WOW64 AltTargetDomainName;
KERB_CRYPTO_KEY_WOW64 SessionKey;
ULONG TicketFlags;
ULONG Flags;
LARGE_INTEGER KeyExpirationTime;
LARGE_INTEGER StartTime;
LARGE_INTEGER EndTime;
LARGE_INTEGER RenewUntil;
LARGE_INTEGER TimeSkew;
ULONG EncodedTicketSize;
ULONG EncodedTicket;
}
KERB_EXTERNAL_TICKET_WOW64, *PKERB_EXTERNAL_TICKET_WOW64;
typedef struct _KERB_EXTERNAL_TICKET_EX_WOW64
{
PKERB_EXTERNAL_NAME_WOW64 ClientName;
PKERB_EXTERNAL_NAME_WOW64 ServiceName;
PKERB_EXTERNAL_NAME_WOW64 TargetName;
UNICODE_STRING_WOW64 ClientRealm;
UNICODE_STRING_WOW64 ServerRealm;
UNICODE_STRING_WOW64 TargetDomainName;
UNICODE_STRING_WOW64 AltTargetDomainName;
KERB_CRYPTO_KEY_WOW64 SessionKey;
ULONG TicketFlags;
ULONG Flags;
LARGE_INTEGER KeyExpirationTime;
LARGE_INTEGER StartTime;
LARGE_INTEGER EndTime;
LARGE_INTEGER RenewUntil;
LARGE_INTEGER TimeSkew;
PKERB_NET_ADDRESSES TicketAddresses;
PKERB_AUTH_DATA AuthorizationData;
_KERB_EXTERNAL_TICKET_EX_WOW64 * SecondTicket;
ULONG EncodedTicketSize;
PUCHAR EncodedTicket;
}
KERB_EXTERNAL_TICKET_EX_WOW64, *PKERB_EXTERNAL_TICKET_EX_WOW64;
#define RELOCATE_WOW_UNICODE_STRING(WOWString, NativeString, Offset) \
NativeString.Length = WOWString.Length; \
NativeString.MaximumLength = WOWString.MaximumLength; \
NativeString.Buffer = (LPWSTR) ((LPBYTE) UlongToPtr(WOWString.Buffer) + Offset);
//+-------------------------------------------------------------------------
//
// Function: KerbPutWOWString
//
// Synopsis: Copies a UNICODE_STRING into a buffer
//
// Effects:
//
// Arguments: InputString - String to 'put'
// OutputString - Receives 'put' string
// Offset - Difference in addresses of local and client buffers.
// Where - Location in local buffer to place string.
//
// Requires:
//
// Returns:
//
// Notes: This code is (effectively) duplicated in
// KerbPutString. Make sure any changes
// made here are applied there as well.
//
//--------------------------------------------------------------------------
VOID
KerbPutWOWString(
IN PUNICODE_STRING InputString,
OUT PUNICODE_STRING_WOW64 OutputString,
IN LONG_PTR Offset,
IN OUT PBYTE * Where
)
{
OutputString->Length = OutputString->MaximumLength = InputString->Length;
OutputString->Buffer = PtrToUlong (*Where + Offset);
RtlCopyMemory(
*Where,
InputString->Buffer,
InputString->Length
);
*Where += InputString->Length;
}
//+-------------------------------------------------------------------------
//
// Function: KerbPutWOWKdcName
//
// Synopsis: Copies a Kdc name to a buffer
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes: This code is (effectively) duplicated in
// KerbPutKdcName. Make sure any changes
// made here are applied there as well.
//
//--------------------------------------------------------------------------
VOID
KerbPutWOWKdcName(
IN PKERB_INTERNAL_NAME InputName,
OUT PULONG OutputName,
IN LONG_PTR Offset,
IN OUT PBYTE * Where
)
{
ULONG Index;
PKERB_INTERNAL_NAME_WOW64 LocalName = (PKERB_INTERNAL_NAME_WOW64) *Where;
if (!ARGUMENT_PRESENT(InputName))
{
*OutputName = NULL;
return;
}
*Where += sizeof(KERB_INTERNAL_NAME_WOW64) - sizeof(UNICODE_STRING_WOW64) +
InputName->NameCount * sizeof(UNICODE_STRING_WOW64);
LocalName->NameType = InputName->NameType;
LocalName->NameCount = InputName->NameCount;
for (Index = 0; Index < InputName->NameCount ; Index++ )
{
LocalName->Names[Index].Length =
LocalName->Names[Index].MaximumLength =
InputName->Names[Index].Length;
LocalName->Names[Index].Buffer = PtrToUlong(*Where + Offset);
RtlCopyMemory(*Where,
InputName->Names[Index].Buffer,
InputName->Names[Index].Length);
*Where += InputName->Names[Index].Length;
}
*Where = (PBYTE) ROUND_UP_POINTER(*Where, sizeof(ULONG));
*OutputName = PtrToUlong((PBYTE) LocalName + Offset);
}
//+-------------------------------------------------------------------------
//
// Function: KerbPutKdcNameAsWOWString
//
// Synopsis: Copies a KERB_INTERNAL_NAME into a buffer
//
// Effects:
//
// Arguments: InputString - String to 'put'
// OutputString - Receives 'put' string
// Offset - Difference in addresses of local and client buffers.
// Where - Location in local buffer to place string.
//
// Requires:
//
// Returns:
//
// Notes: This code is (effectively) duplicated in
// KerbPutKdcNameAsString. Make sure any
// changes made here are applied there as well.
//
//--------------------------------------------------------------------------
VOID
KerbPutKdcNameAsWOWString(
IN PKERB_INTERNAL_NAME InputName,
OUT PUNICODE_STRING_WOW64 OutputName,
IN LONG_PTR Offset,
IN OUT PBYTE * Where
)
{
USHORT Index;
OutputName->Buffer = PtrToUlong (*Where + Offset);
OutputName->Length = 0;
OutputName->MaximumLength = 0;
for (Index = 0; Index < InputName->NameCount ; Index++ )
{
RtlCopyMemory(
*Where,
InputName->Names[Index].Buffer,
InputName->Names[Index].Length
);
*Where += InputName->Names[Index].Length;
OutputName->Length += InputName->Names[Index].Length;
if (Index == (InputName->NameCount - 1))
{
*((LPWSTR) *Where) = L'\0';
OutputName->MaximumLength = OutputName->Length + sizeof(WCHAR);
}
else
{
*((LPWSTR) *Where) = L'/';
OutputName->Length += sizeof(WCHAR);
}
*Where += sizeof(WCHAR);
}
}
//+-------------------------------------------------------------------------
//
// Function: KerbPutWOWClientString
//
// Synopsis: Copies a string into a buffer that will be copied to the
// 32-bit client's address space
//
// Effects:
//
// Arguments: Where - Location in local buffer to place string.
// Delta - Difference in addresses of local and client buffers.
// OutString - Receives 'put' string
// InString - String to 'put'
//
// Requires:
//
// Returns:
//
// Notes: This code is (effectively) duplicated in
// KerbPutClientString. Make sure any changes
// made here are applied there as well.
//
//--------------------------------------------------------------------------
VOID
KerbPutWOWClientString(
IN OUT PUCHAR * Where,
IN LONG_PTR Delta,
IN PUNICODE_STRING_WOW64 OutString,
IN PUNICODE_STRING InString
)
{
if (InString->Length == 0)
{
OutString->Buffer = 0;
OutString->Length = OutString->MaximumLength = 0;
}
else
{
RtlCopyMemory(*Where,
InString->Buffer,
InString->Length);
OutString->Buffer = PtrToUlong(*Where + Delta);
OutString->Length = InString->Length;
*Where += InString->Length;
*(LPWSTR) (*Where) = L'\0';
*Where += sizeof(WCHAR);
OutString->MaximumLength = OutString->Length + sizeof(WCHAR);
}
}
//+-------------------------------------------------------------------------
//
// Function: KerbWOWNameLength
//
// Synopsis: returns length in bytes of variable portion
// of KERB_INTERNAL_NAME
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes: This code is (effectively) duplicated in
// KerbNameLength. Make sure any changes
// made here are applied there as well.
//
//--------------------------------------------------------------------------
ULONG
KerbWOWNameLength(
IN PKERB_INTERNAL_NAME Name
)
{
ULONG Length = 0;
ULONG Index;
if (!ARGUMENT_PRESENT(Name))
{
return 0;
}
Length = sizeof(KERB_INTERNAL_NAME_WOW64)
- sizeof(UNICODE_STRING_WOW64)
+ Name->NameCount * sizeof(UNICODE_STRING_WOW64);
for (Index = 0; Index < Name->NameCount ;Index++ )
{
Length += Name->Names[Index].Length;
}
Length = ROUND_UP_COUNT(Length, sizeof(ULONG));
return Length;
}
//+-------------------------------------------------------------------------
//
// Function: KerbConvertWOWLogonBuffer
//
// Synopsis: Converts logon buffers passed in from WOW clients to 64-bit
//
// Effects:
//
// Arguments: ProtocolSubmitBuffer -- original 32-bit logon buffer
// pSubmitBufferSize -- size of the 32-bit logon buffer
// MessageType -- format of the logon buffer
// ppTempSubmitBuffer -- filled in with the converted buffer
//
// Requires:
//
// Returns:
//
// Notes: This routine allocates the converted buffer and returns it
// on success. It is the caller's responsibility to free it.
//
//
//--------------------------------------------------------------------------
NTSTATUS
KerbConvertWOWLogonBuffer(
IN PVOID ProtocolSubmitBuffer,
IN PVOID ClientBufferBase,
IN OUT PULONG pSubmitBufferSize,
IN KERB_LOGON_SUBMIT_TYPE MessageType,
OUT PVOID *ppTempSubmitBuffer
)
{
NTSTATUS Status = STATUS_SUCCESS;
PVOID pTempBuffer = NULL;
ULONG dwBufferSize = *pSubmitBufferSize;
switch (MessageType)
{
case KerbInteractiveLogon:
case KerbWorkstationUnlockLogon:
{
PKERB_INTERACTIVE_LOGON Logon;
PKERB_INTERACTIVE_LOGON_WOW64 LogonWOW;
DWORD dwOffset;
DWORD dwWOWOffset;
//
// Scale up the size and add on 3 PVOIDs for the worst-case
// scenario to align the three embedded UNICODE_STRINGs
//
dwBufferSize += sizeof(KERB_INTERACTIVE_LOGON)
- sizeof(KERB_INTERACTIVE_LOGON_WOW64);
if (dwBufferSize < sizeof(KERB_INTERACTIVE_LOGON))
{
DebugLog((DEB_ERROR,
"Submit buffer to logon too small: %d. %ws, line %d\n",
dwBufferSize,
THIS_FILE,
__LINE__));
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
pTempBuffer = KerbAllocate(dwBufferSize);
if (pTempBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Logon = (PKERB_INTERACTIVE_LOGON) pTempBuffer;
LogonWOW = (PKERB_INTERACTIVE_LOGON_WOW64) ProtocolSubmitBuffer;
Logon->MessageType = LogonWOW->MessageType;
dwOffset = sizeof(KERB_INTERACTIVE_LOGON);
dwWOWOffset = sizeof(KERB_INTERACTIVE_LOGON_WOW64);
if (MessageType == KerbWorkstationUnlockLogon)
{
if (dwBufferSize < sizeof(KERB_INTERACTIVE_UNLOCK_LOGON))
{
DebugLog((DEB_ERROR,
"Submit buffer to logon too small: %d. %ws, line %d\n",
dwBufferSize,
THIS_FILE,
__LINE__));
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
//
// One additional field for this type (a LUID)
//
PKERB_INTERACTIVE_UNLOCK_LOGON Unlock;
PKERB_INTERACTIVE_UNLOCK_LOGON_WOW64 UnlockWOW;
Unlock = (PKERB_INTERACTIVE_UNLOCK_LOGON) pTempBuffer;
UnlockWOW = (PKERB_INTERACTIVE_UNLOCK_LOGON_WOW64) ProtocolSubmitBuffer;
Unlock->LogonId = UnlockWOW->LogonId;
dwOffset = sizeof(KERB_INTERACTIVE_UNLOCK_LOGON);
dwWOWOffset = sizeof(KERB_INTERACTIVE_UNLOCK_LOGON_WOW64);
}
//
// Copy the variable-length data
//
RtlCopyMemory((LPBYTE) Logon + dwOffset,
(LPBYTE) LogonWOW + dwWOWOffset,
*pSubmitBufferSize - dwWOWOffset);
//
// Set up the pointers in the native struct
//
RELOCATE_WOW_UNICODE_STRING(LogonWOW->LogonDomainName,
Logon->LogonDomainName,
dwOffset - dwWOWOffset);
RELOCATE_WOW_UNICODE_STRING(LogonWOW->UserName,
Logon->UserName,
dwOffset - dwWOWOffset);
RELOCATE_WOW_UNICODE_STRING(LogonWOW->Password,
Logon->Password,
dwOffset - dwWOWOffset);
break;
}
case KerbSmartCardLogon:
case KerbSmartCardUnlockLogon:
{
PKERB_SMART_CARD_LOGON Logon;
PKERB_SMART_CARD_LOGON_WOW64 LogonWOW;
DWORD dwOffset;
DWORD dwWOWOffset;
//
// Scale up the size and add on 2 PVOIDs for the worst-case
// scenario to align the embedded UNICODE_STRING and CspData
//
dwBufferSize += sizeof(KERB_SMART_CARD_LOGON)
- sizeof(KERB_SMART_CARD_LOGON_WOW64);
if (dwBufferSize < sizeof(KERB_SMART_CARD_LOGON))
{
DebugLog((DEB_ERROR,
"Submit buffer to logon too small: %d. %ws, line %d\n",
dwBufferSize,
THIS_FILE,
__LINE__));
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
pTempBuffer = KerbAllocate(dwBufferSize);
if (pTempBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Logon = (PKERB_SMART_CARD_LOGON) pTempBuffer;
LogonWOW = (PKERB_SMART_CARD_LOGON_WOW64) ProtocolSubmitBuffer;
Logon->MessageType = LogonWOW->MessageType;
Logon->CspDataLength = LogonWOW->CspDataLength;
dwOffset = sizeof(KERB_SMART_CARD_LOGON);
dwWOWOffset = sizeof(KERB_SMART_CARD_LOGON_WOW64);
if (MessageType == KerbSmartCardUnlockLogon)
{
if (dwBufferSize < sizeof(KERB_SMART_CARD_UNLOCK_LOGON))
{
DebugLog((DEB_ERROR,
"Submit buffer to logon too small: %d. %ws, line %d\n",
dwBufferSize,
THIS_FILE,
__LINE__));
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
//
// One additional field for this type (a LUID)
//
PKERB_SMART_CARD_UNLOCK_LOGON Unlock;
PKERB_SMART_CARD_UNLOCK_LOGON_WOW64 UnlockWOW;
Unlock = (PKERB_SMART_CARD_UNLOCK_LOGON) pTempBuffer;
UnlockWOW = (PKERB_SMART_CARD_UNLOCK_LOGON_WOW64) ProtocolSubmitBuffer;
Unlock->LogonId = UnlockWOW->LogonId;
dwOffset = sizeof(KERB_SMART_CARD_UNLOCK_LOGON);
dwWOWOffset = sizeof(KERB_SMART_CARD_UNLOCK_LOGON_WOW64);
}
//
// Copy the variable-length data
//
RtlCopyMemory((LPBYTE) Logon + dwOffset,
(LPBYTE) LogonWOW + dwWOWOffset,
*pSubmitBufferSize - dwWOWOffset);
//
// Set up the pointers in the native struct
//
RELOCATE_WOW_UNICODE_STRING(LogonWOW->Pin,
Logon->Pin,
dwOffset - dwWOWOffset);
Logon->CspData = (PUCHAR) ((LPBYTE) UlongToPtr(LogonWOW->CspData) + (dwOffset - dwWOWOffset));
break;
}
case KerbTicketLogon:
case KerbTicketUnlockLogon:
{
PKERB_TICKET_LOGON Logon;
PKERB_TICKET_LOGON_WOW64 LogonWOW;
DWORD dwOffset;
DWORD dwWOWOffset;
//
// Scale up the size and add on 2 PVOIDs for the worst-case
// scenario to align the two embedded pointers
//
dwBufferSize += sizeof(KERB_TICKET_LOGON)
- sizeof(KERB_TICKET_LOGON_WOW64);
if (dwBufferSize < sizeof(KERB_TICKET_LOGON))
{
DebugLog((DEB_ERROR,
"Submit buffer to logon too small: %d. %ws, line %d\n",
dwBufferSize,
THIS_FILE,
__LINE__));
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
pTempBuffer = KerbAllocate(dwBufferSize);
if (pTempBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Logon = (PKERB_TICKET_LOGON) pTempBuffer;
LogonWOW = (PKERB_TICKET_LOGON_WOW64) ProtocolSubmitBuffer;
Logon->MessageType = LogonWOW->MessageType;
Logon->Flags = LogonWOW->Flags;
Logon->ServiceTicketLength = LogonWOW->ServiceTicketLength;
Logon->TicketGrantingTicketLength = LogonWOW->TicketGrantingTicketLength;
dwOffset = sizeof(KERB_TICKET_LOGON);
dwWOWOffset = sizeof(KERB_TICKET_LOGON_WOW64);
if (MessageType == KerbTicketUnlockLogon)
{
if (dwBufferSize < sizeof(KERB_TICKET_UNLOCK_LOGON))
{
DebugLog((DEB_ERROR,
"Submit buffer to logon too small: %d. %ws, line %d\n",
dwBufferSize,
THIS_FILE,
__LINE__));
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
//
// One additional field for this type (a LUID)
//
PKERB_TICKET_UNLOCK_LOGON Unlock;
PKERB_TICKET_UNLOCK_LOGON_WOW64 UnlockWOW;
Unlock = (PKERB_TICKET_UNLOCK_LOGON) pTempBuffer;
UnlockWOW = (PKERB_TICKET_UNLOCK_LOGON_WOW64) ProtocolSubmitBuffer;
Unlock->LogonId = UnlockWOW->LogonId;
dwOffset = sizeof(KERB_TICKET_UNLOCK_LOGON);
dwWOWOffset = sizeof(KERB_TICKET_UNLOCK_LOGON_WOW64);
}
//
// Copy the variable-length data
//
RtlCopyMemory((LPBYTE) Logon + dwOffset,
(LPBYTE) LogonWOW + dwWOWOffset,
*pSubmitBufferSize - dwWOWOffset);
//
// Set up the pointers in the native struct
//
Logon->ServiceTicket = (PUCHAR) ((LPBYTE) UlongToPtr(LogonWOW->ServiceTicket)
+ (dwOffset - dwWOWOffset));
Logon->TicketGrantingTicket = (PUCHAR) ((LPBYTE) UlongToPtr(LogonWOW->TicketGrantingTicket)
+ (dwOffset - dwWOWOffset));
break;
}
default:
DebugLog((DEB_ERROR,
"Invalid info class to logon: %d. %ws, line %d\n",
MessageType,
THIS_FILE,
__LINE__));
Status = STATUS_INVALID_INFO_CLASS;
goto Cleanup;
}
*pSubmitBufferSize = dwBufferSize;
*ppTempSubmitBuffer = pTempBuffer;
return STATUS_SUCCESS;
Cleanup:
ASSERT(!NT_SUCCESS(Status));
if (pTempBuffer)
{
KerbFree(pTempBuffer);
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: KerbAllocateInteractiveWOWProfile
//
// Synopsis: This allocates and fills in the interactive profile for
// a WOW64 client.
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
//
// Notes: This code is (effectively) duplicated in
// KerbAllocateInteractiveBuffer. Make sure any
// changes made here are applied there as well.
//
//--------------------------------------------------------------------------
NTSTATUS
KerbAllocateInteractiveWOWBuffer(
OUT PKERB_INTERACTIVE_PROFILE *ProfileBuffer,
OUT PULONG ProfileBufferSize,
IN PNETLOGON_VALIDATION_SAM_INFO3 UserInfo,
IN PKERB_LOGON_SESSION LogonSession,
IN OPTIONAL PKERB_ENCRYPTED_TICKET LogonTicket,
IN OPTIONAL PKERB_INTERACTIVE_LOGON KerbLogonInfo,
IN PUCHAR *pClientBufferBase,
IN BOOLEAN BuildSmartCardProfile,
IN BOOLEAN BuildTicketProfile
)
{
NTSTATUS Status = STATUS_SUCCESS;
PKERB_INTERACTIVE_PROFILE_WOW64 LocalProfileBuffer = NULL;
PKERB_SMART_CARD_PROFILE_WOW64 SmartCardProfile = NULL;
PKERB_TICKET_PROFILE_WOW64 TicketProfile = NULL;
LONG_PTR Delta = 0;
PUCHAR Where = NULL;
if (BuildSmartCardProfile)
{
*ProfileBufferSize = sizeof(KERB_SMART_CARD_PROFILE_WOW64) +
LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext->cbCertEncoded;
}
else if (BuildTicketProfile)
{
*ProfileBufferSize = sizeof(KERB_TICKET_PROFILE_WOW64) +
LogonTicket->key.keyvalue.length;
}
else
{
*ProfileBufferSize = sizeof(KERB_INTERACTIVE_PROFILE_WOW64);
}
*ProfileBufferSize +=
UserInfo->LogonScript.Length + sizeof(WCHAR) +
UserInfo->HomeDirectory.Length + sizeof(WCHAR) +
UserInfo->HomeDirectoryDrive.Length + sizeof(WCHAR) +
UserInfo->FullName.Length + sizeof(WCHAR) +
UserInfo->ProfilePath.Length + sizeof(WCHAR) +
UserInfo->LogonServer.Length + sizeof(WCHAR);
LocalProfileBuffer = (PKERB_INTERACTIVE_PROFILE_WOW64) KerbAllocate(*ProfileBufferSize);
if (LocalProfileBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Status = LsaFunctions->AllocateClientBuffer(
NULL,
*ProfileBufferSize,
(PVOID *) pClientBufferBase
);
if ( !NT_SUCCESS( Status ) )
{
goto Cleanup;
}
Delta = (LONG_PTR) (*pClientBufferBase - (PUCHAR) LocalProfileBuffer) ;
//
// Don't walk over smart card data
//
if (BuildSmartCardProfile)
{
Where = (PUCHAR) ((PKERB_SMART_CARD_PROFILE_WOW64) LocalProfileBuffer + 1);
}
else if (BuildTicketProfile)
{
Where = (PUCHAR) ((PKERB_TICKET_PROFILE_WOW64) LocalProfileBuffer + 1);
}
else
{
Where = (PUCHAR) (LocalProfileBuffer + 1);
}
//
// Copy the scalar fields into the profile buffer.
//
LocalProfileBuffer->MessageType = KerbInteractiveProfile;
LocalProfileBuffer->LogonCount = UserInfo->LogonCount;
LocalProfileBuffer->BadPasswordCount= UserInfo->BadPasswordCount;
OLD_TO_NEW_LARGE_INTEGER( UserInfo->LogonTime,
LocalProfileBuffer->LogonTime );
OLD_TO_NEW_LARGE_INTEGER( UserInfo->LogoffTime,
LocalProfileBuffer->LogoffTime );
OLD_TO_NEW_LARGE_INTEGER( UserInfo->KickOffTime,
LocalProfileBuffer->KickOffTime );
OLD_TO_NEW_LARGE_INTEGER( UserInfo->PasswordLastSet,
LocalProfileBuffer->PasswordLastSet );
OLD_TO_NEW_LARGE_INTEGER( UserInfo->PasswordCanChange,
LocalProfileBuffer->PasswordCanChange );
OLD_TO_NEW_LARGE_INTEGER( UserInfo->PasswordMustChange,
LocalProfileBuffer->PasswordMustChange );
LocalProfileBuffer->UserFlags = UserInfo->UserFlags;
//
// Copy the Unicode strings into the profile buffer.
//
KerbPutWOWClientString(&Where,
Delta,
&LocalProfileBuffer->LogonScript,
&UserInfo->LogonScript );
KerbPutWOWClientString(&Where,
Delta,
&LocalProfileBuffer->HomeDirectory,
&UserInfo->HomeDirectory );
KerbPutWOWClientString(&Where,
Delta,
&LocalProfileBuffer->HomeDirectoryDrive,
&UserInfo->HomeDirectoryDrive );
KerbPutWOWClientString(&Where,
Delta,
&LocalProfileBuffer->FullName,
&UserInfo->FullName );
KerbPutWOWClientString(&Where,
Delta,
&LocalProfileBuffer->ProfilePath,
&UserInfo->ProfilePath );
KerbPutWOWClientString(&Where,
Delta,
&LocalProfileBuffer->LogonServer,
&UserInfo->LogonServer );
if (BuildSmartCardProfile)
{
LocalProfileBuffer->MessageType = KerbSmartCardProfile;
SmartCardProfile = (PKERB_SMART_CARD_PROFILE_WOW64) LocalProfileBuffer;
SmartCardProfile->CertificateSize = LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext->cbCertEncoded;
SmartCardProfile->CertificateData = PtrToUlong(Where + Delta);
RtlCopyMemory(Where,
LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext->pbCertEncoded,
SmartCardProfile->CertificateSize);
Where += SmartCardProfile->CertificateSize;
}
else if (BuildTicketProfile)
{
LocalProfileBuffer->MessageType = KerbTicketProfile;
TicketProfile = (PKERB_TICKET_PROFILE_WOW64) LocalProfileBuffer;
//
// If the key is exportable or we are domestic, return the key
//
if (KerbGlobalStrongEncryptionPermitted || KerbIsKeyExportable(&LogonTicket->key))
{
TicketProfile->SessionKey.KeyType = LogonTicket->key.keytype;
TicketProfile->SessionKey.Length = LogonTicket->key.keyvalue.length;
TicketProfile->SessionKey.Value = PtrToUlong(Where + Delta);
RtlCopyMemory(Where,
LogonTicket->key.keyvalue.value,
LogonTicket->key.keyvalue.length);
Where += TicketProfile->SessionKey.Length;
}
}
Cleanup:
if (!NT_SUCCESS(Status))
{
LsaFunctions->FreeClientBuffer(NULL, *pClientBufferBase);
if (LocalProfileBuffer != NULL)
{
KerbFree(LocalProfileBuffer);
}
}
else
{
*ProfileBuffer = (PKERB_INTERACTIVE_PROFILE) LocalProfileBuffer;
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: KerbPackExternalWOWTicket
//
// Synopsis: This allocates and fills in the external ticket for
// a WOW64 client.
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
//
// Notes: This code is (effectively) duplicated in
// KerbPackExternalTicket. Make sure any
// changes made here are applied there as well.
//
//--------------------------------------------------------------------------
NTSTATUS
KerbPackExternalWOWTicket(
IN PKERB_TICKET_CACHE_ENTRY pCacheEntry,
IN PKERB_MESSAGE_BUFFER pEncodedTicket,
OUT PKERB_EXTERNAL_TICKET *pTicketResponse,
OUT PBYTE *pClientTicketResponse,
OUT PULONG pTicketSize
)
{
PKERB_EXTERNAL_TICKET_WOW64 TicketResponseWOW = NULL;
PBYTE ClientTicketResponseWOW = NULL;
ULONG ulTicketSize;
ULONG Offset;
PUCHAR Where;
NTSTATUS Status;
ulTicketSize = sizeof(KERB_EXTERNAL_TICKET_WOW64) +
pCacheEntry->DomainName.Length +
pCacheEntry->TargetDomainName.Length +
pCacheEntry->AltTargetDomainName.Length +
pCacheEntry->SessionKey.keyvalue.length +
KerbWOWNameLength(pCacheEntry->ServiceName) +
KerbWOWNameLength(pCacheEntry->TargetName) +
KerbWOWNameLength(pCacheEntry->ClientName) +
pEncodedTicket->BufferSize;
//
// Now allocate two copies of the structure - one in our process,
// one in the client's process. We then build the structure in our
// process but with pointer valid in the client's process
//
TicketResponseWOW = (PKERB_EXTERNAL_TICKET_WOW64) KerbAllocate(ulTicketSize);
if (TicketResponseWOW == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Status = LsaFunctions->AllocateClientBuffer(NULL,
ulTicketSize,
(PVOID *) &ClientTicketResponseWOW);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Offset = (ULONG) (ClientTicketResponseWOW - (PBYTE) TicketResponseWOW);
Where = ((PUCHAR) (TicketResponseWOW + 1));
//
// Copy the non-pointer fields
//
TicketResponseWOW->TicketFlags = pCacheEntry->TicketFlags;
TicketResponseWOW->Flags = 0;
TicketResponseWOW->KeyExpirationTime = pCacheEntry->KeyExpirationTime;
TicketResponseWOW->StartTime = pCacheEntry->StartTime;
TicketResponseWOW->EndTime = pCacheEntry->EndTime;
TicketResponseWOW->RenewUntil = pCacheEntry->RenewUntil;
TicketResponseWOW->TimeSkew = pCacheEntry->TimeSkew;
TicketResponseWOW->SessionKey.KeyType = pCacheEntry->SessionKey.keytype;
//
// Copy the structure to the client's address space
//
//
// These are 32-bit PVOID (i.e., ULONG) aligned
//
//
// Make sure the two name types are the same
//
DsysAssert(sizeof(KERB_INTERNAL_NAME_WOW64) == sizeof(KERB_EXTERNAL_NAME_WOW64));
DsysAssert(FIELD_OFFSET(KERB_INTERNAL_NAME_WOW64,NameType) == FIELD_OFFSET(KERB_EXTERNAL_NAME_WOW64,NameType));
DsysAssert(FIELD_OFFSET(KERB_INTERNAL_NAME_WOW64,NameCount) == FIELD_OFFSET(KERB_EXTERNAL_NAME_WOW64,NameCount));
DsysAssert(FIELD_OFFSET(KERB_INTERNAL_NAME_WOW64,Names) == FIELD_OFFSET(KERB_EXTERNAL_NAME_WOW64,Names));
KerbPutWOWKdcName(pCacheEntry->ServiceName,
&TicketResponseWOW->ServiceName,
Offset,
&Where);
KerbPutWOWKdcName(pCacheEntry->TargetName,
&TicketResponseWOW->TargetName,
Offset,
&Where);
KerbPutWOWKdcName(pCacheEntry->ClientName,
&TicketResponseWOW->ClientName,
Offset,
&Where);
//
// From here on, they are WCHAR aligned
//
KerbPutWOWString(&pCacheEntry->DomainName,
&TicketResponseWOW->DomainName,
Offset,
&Where);
KerbPutWOWString(&pCacheEntry->TargetDomainName,
&TicketResponseWOW->TargetDomainName,
Offset,
&Where);
KerbPutWOWString(&pCacheEntry->AltTargetDomainName,
&TicketResponseWOW->AltTargetDomainName,
Offset,
&Where);
//
// And from here they are BYTE aligned
//
TicketResponseWOW->SessionKey.Value = PtrToUlong(Where + Offset);
RtlCopyMemory(Where,
pCacheEntry->SessionKey.keyvalue.value,
pCacheEntry->SessionKey.keyvalue.length);
Where += pCacheEntry->SessionKey.keyvalue.length;
TicketResponseWOW->SessionKey.Length = pCacheEntry->SessionKey.keyvalue.length;
TicketResponseWOW->EncodedTicketSize = pEncodedTicket->BufferSize;
TicketResponseWOW->EncodedTicket = PtrToUlong(Where + Offset);
RtlCopyMemory(Where,
pEncodedTicket->Buffer,
pEncodedTicket->BufferSize);
Where += pEncodedTicket->BufferSize;
DsysAssert(Where - ((PUCHAR) TicketResponseWOW) == (LONG_PTR) ulTicketSize);
*pTicketResponse = (PKERB_EXTERNAL_TICKET) TicketResponseWOW;
*pClientTicketResponse = ClientTicketResponseWOW;
*pTicketSize = ulTicketSize;
return STATUS_SUCCESS;
Cleanup:
if (TicketResponseWOW != NULL)
{
KerbFree(TicketResponseWOW);
}
if (ClientTicketResponseWOW != NULL)
{
LsaFunctions->FreeClientBuffer(NULL, ClientTicketResponseWOW);
}
*pTicketResponse = NULL;
*pClientTicketResponse = NULL;
*pTicketSize = 0;
return Status;
}
#endif // _WIN64