//+----------------------------------------------------------------------- // // 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 #include #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