|
|
//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 1992 - 1999
//
// File: tktlogon.cxx
//
// Contents: Code for proxy logon for the Kerberos package
//
//
// History: 15-March Created MikeSw
//
//------------------------------------------------------------------------
#include <kerb.hxx>
#include <kerbp.h>
#ifdef RETAIL_LOG_SUPPORT
static TCHAR THIS_FILE[]=TEXT(__FILE__); #endif
//+-------------------------------------------------------------------------
//
// Function: KerbCreateTicketLogonSession
//
// Synopsis: Does all the work for a ticket logon, removing it from
// LsaApLogonUserEx2
//
// Effects:
//
// Arguments: WorkstationTicket - ticket to workstation. The ticket
// cache entry is pretty much empty except for
// the ticket, and is not linked
// ForwardedTgt - receives pointers into the Protocol
// SubmitBuffer to the forwarded TGT.
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS KerbCreateTicketLogonSession( IN PVOID ProtocolSubmitBuffer, IN PVOID ClientBufferBase, IN ULONG SubmitBufferSize, IN SECURITY_LOGON_TYPE LogonType, OUT PKERB_LOGON_SESSION * NewLogonSession, OUT PLUID LogonId, OUT PKERB_TICKET_CACHE_ENTRY * WorkstationTicket, OUT PKERB_MESSAGE_BUFFER ForwardedTgt ) { NTSTATUS Status = STATUS_SUCCESS; PKERB_TICKET_LOGON LogonInfo = NULL; PKERB_LOGON_SESSION LogonSession = NULL; KERB_KDC_REPLY KdcReply = {0}; ULONG_PTR Offset; UNICODE_STRING EmptyString = {0}; PKERB_TICKET Ticket = NULL; KERBERR KerbErr;
*WorkstationTicket = NULL; ForwardedTgt->Buffer = NULL; ForwardedTgt->BufferSize = 0;
//
// Pull the interesting information out of the submit buffer
//
if (SubmitBufferSize < sizeof(KERB_TICKET_LOGON)) { DebugLog((DEB_ERROR,"Submit buffer to logon too small: %d. %ws, line %d\n",SubmitBufferSize, THIS_FILE, __LINE__)); Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
LogonInfo = (PKERB_TICKET_LOGON) ProtocolSubmitBuffer;
DsysAssert((LogonInfo->MessageType == KerbTicketLogon) || (LogonInfo->MessageType == KerbTicketUnlockLogon));
//
// Relocate any pointers to be relative to 'LogonInfo'
//
Offset = ((PUCHAR) LogonInfo->ServiceTicket) - ((PUCHAR)ClientBufferBase); if ( (Offset >= SubmitBufferSize) || (Offset + LogonInfo->ServiceTicketLength > SubmitBufferSize)) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; } LogonInfo->ServiceTicket = (PUCHAR) ProtocolSubmitBuffer + Offset;
if (LogonInfo->TicketGrantingTicketLength != 0) { if (LogonInfo->TicketGrantingTicket == NULL) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
Offset = ((PUCHAR) LogonInfo->TicketGrantingTicket) - ((PUCHAR)ClientBufferBase); if ( (Offset >= SubmitBufferSize) || (Offset + LogonInfo->TicketGrantingTicketLength > SubmitBufferSize)) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; } LogonInfo->TicketGrantingTicket = (PUCHAR) ProtocolSubmitBuffer + Offset; ForwardedTgt->BufferSize = LogonInfo->TicketGrantingTicketLength; ForwardedTgt->Buffer = LogonInfo->TicketGrantingTicket; }
//
// Allocate a locally unique ID for this logon session. We will
// create it in the LSA just before returning.
//
Status = NtAllocateLocallyUniqueId( LogonId ); if (!NT_SUCCESS(Status)) { DebugLog((DEB_ERROR,"Failed to allocate locally unique ID: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__)); goto Cleanup; }
//
// Build a logon session to hold all this information
//
Status = KerbCreateLogonSession( LogonId, &EmptyString, &EmptyString, NULL, // no password
NULL, // no old password
0, // no password options
0, FALSE, // no dups - this is a primary logon
&LogonSession ); if (!NT_SUCCESS(Status)) { goto Cleanup; }
//
// Unpack the supplied service ticket
//
KerbErr = KerbUnpackData( LogonInfo->ServiceTicket, LogonInfo->ServiceTicketLength, KERB_TICKET_PDU, (PVOID *) &Ticket ); if (!KERB_SUCCESS(KerbErr)) { DebugLog((DEB_ERROR,"Failed to unpack service ticket in ticket logon\n")); Status = KerbMapKerbError(KerbErr); goto Cleanup; }
//
// Build a ticket structure from the service ticket.
//
KdcReply.ticket = *Ticket;
Status = KerbCreateTicketCacheEntry( &KdcReply, NULL, // no kdc reply
NULL, // no target name
NULL, // no target realm
0, // no flags
NULL, // no ticket cache
NULL, // no credential key
WorkstationTicket );
if (!NT_SUCCESS(Status)) { goto Cleanup; }
//
// Return the new logon session.
//
*NewLogonSession = LogonSession; LogonSession = NULL;
Cleanup:
if (!NT_SUCCESS(Status)) { if (LogonSession != NULL) { KerbReferenceLogonSessionByPointer(LogonSession, TRUE); KerbDereferenceLogonSession(LogonSession); } }
if (Ticket != NULL) { KerbFreeData(KERB_TICKET_PDU, Ticket); }
return(Status); }
//+-------------------------------------------------------------------------
//
// Function: KerbExtractForwardedTgt
//
// Synopsis: Extracts a forwarded TGT from its encoded representation
// and sticks it in the logon session ticket cache. This
// also updates the user name & domain name in the
// logon session, if they aren't present.
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS KerbExtractForwardedTgt( IN PKERB_LOGON_SESSION LogonSession, IN PKERB_MESSAGE_BUFFER ForwardedTgt, IN PKERB_ENCRYPTED_TICKET WorkstationTicket ) { PKERB_CRED KerbCred = NULL; PKERB_ENCRYPTED_CRED EncryptedCred = NULL; KERBERR KerbErr; NTSTATUS Status = STATUS_SUCCESS;
D_DebugLog((DEB_TRACE, "Extracting a forwarded TGT\n"));
KerbErr = KerbUnpackKerbCred( ForwardedTgt->Buffer, ForwardedTgt->BufferSize, &KerbCred ); if (!KERB_SUCCESS(KerbErr)) { DebugLog((DEB_WARN, "Failed to unpack kerb cred for forwaded tgt\n")); Status = KerbMapKerbError(KerbErr); goto Cleanup;
}
//
// Now decrypt the encrypted part of the KerbCred.
//
KerbErr = KerbDecryptDataEx( &KerbCred->encrypted_part, &WorkstationTicket->key, KERB_CRED_SALT, (PULONG) &KerbCred->encrypted_part.cipher_text.length, KerbCred->encrypted_part.cipher_text.value );
if (!KERB_SUCCESS(KerbErr)) { DebugLog((DEB_ERROR,"Failed to decrypt KERB_CRED: 0x%x. %ws, line %d\n",KerbErr, THIS_FILE, __LINE__)); if (KerbErr == KRB_ERR_GENERIC) { Status = KerbMapKerbError(KerbErr); goto Cleanup; } else { Status = STATUS_LOGON_FAILURE;
//
// MIT clients don't encrypt the encrypted part, so drop through
//
} }
//
// Now unpack the encrypted part.
//
KerbErr = KerbUnpackEncryptedCred( KerbCred->encrypted_part.cipher_text.value, KerbCred->encrypted_part.cipher_text.length, &EncryptedCred ); if (!KERB_SUCCESS(KerbErr)) { //
// Use the old status if it is available.
//
if (NT_SUCCESS(Status)) { Status = KerbMapKerbError(KerbErr); } DebugLog((DEB_WARN, "Failed to unpack encrypted cred\n")); goto Cleanup; }
//
// Now build a logon session.
//
Status = KerbCreateLogonSessionFromKerbCred( NULL, WorkstationTicket, KerbCred, EncryptedCred, &LogonSession ); if (!NT_SUCCESS(Status)) { DebugLog((DEB_ERROR,"Failed to create logon session from kerb cred: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__)); goto Cleanup; }
Cleanup: if (EncryptedCred != NULL) { KerbFreeEncryptedCred(EncryptedCred); } if (KerbCred != NULL) { KerbFreeKerbCred(KerbCred); } return(Status);
}
|