windows-nt/Source/XPSP1/NT/ds/security/protocols/kerberos/client2/krbaudit.cxx
2020-09-26 16:20:57 +08:00

333 lines
10 KiB
C++

//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 2001
//
// File: krbaudit.cxx
//
// Contents: Auditing routines
//
//
// History: 27-April-2001 Created kumarp
//
//------------------------------------------------------------------------
#include <kerb.hxx>
#include <kerbp.h>
#include <krbaudit.h>
//+-------------------------------------------------------------------------
//
// Function: KerbGetLogonGuid
//
// Synopsis: Gets a unique ID based on certain fields in the ticket
//
// Arguments: pPrimaryCredentials -- primary credentials
// pKdcReplyBody -- kdc reply structure
// pLogonGuid -- returned GUID
//
// Returns: NTSTATUS code
//
// Notes: The generated GUID is MD5 hash of 3 fields:
// -- client name
// -- client realm
// -- ticket start time
//
// All of these fields are available at client/kdc/server machine.
// this allows us to generate the same unique ID on these machines
// without having to introduce a new field in the ticket.
// This GUID is used in audit events allowing us to correlate
// events on three different machines.
//
//--------------------------------------------------------------------------
NTSTATUS
KerbGetLogonGuid(
IN PKERB_PRIMARY_CREDENTIAL pPrimaryCredentials,
IN PKERB_ENCRYPTED_KDC_REPLY pKdcReplyBody,
OUT LPGUID pLogonGuid
)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
// ISSUE-2001/04/28-kumarp : use KERB_ENCRYPTED_KDC_REPLY_starttime_present
//if ( KdcReplyBody->flags & KERB_ENCRYPTED_KDC_REPLY_starttime_present )
if ( pKdcReplyBody && pPrimaryCredentials )
{
Status = LsaIGetLogonGuid(
&pPrimaryCredentials->UserName,
&pPrimaryCredentials->DomainName,
(PBYTE) &pKdcReplyBody->starttime,
sizeof(KERB_TIME),
pLogonGuid
);
if (!NT_SUCCESS(Status))
{
RtlZeroMemory( pLogonGuid, sizeof(GUID) );
}
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: KerbGenerateAuditForLogonUsingExplicitCreds
//
// Synopsis: Generate an audit event to indicate that somebody logged on
// by supplying explicit credentials.
//
// Arguments: pCurrentUserLogonSession -- logon session of the user
// who supplied credentials of
// another user
// pNewUserPrimaryCredentials -- supplied primary credentials
// pNewUserLogonGuid -- logon GUID for the new logon
//
// Returns: NTSTATUS code
//
// Notes: This event covers credentials obtain from credman
//
//--------------------------------------------------------------------------
NTSTATUS
KerbGenerateAuditForLogonUsingExplicitCreds(
IN PKERB_LOGON_SESSION pCurrentUserLogonSession,
IN PKERB_PRIMARY_CREDENTIAL pNewUserPrimaryCredentials,
IN LPGUID pNewUserLogonGuid
)
{
NTSTATUS Status = STATUS_SUCCESS;
GUID CurrentUserLogonGuid;
LPGUID pCurrentUserLogonGuid = NULL;
PKERB_TICKET_CACHE_ENTRY pTicketCacheEntry = NULL;
UNICODE_STRING OurDomainName = { 0 };
KERB_TIME CurrentUserStartTime = { 0 };
//
// calculate LogonGuid for current logged on user
// we need the following 3 parameters for this:
// -- client name
// -- client realm
// -- ticket start time
//
if ( !(pCurrentUserLogonSession->LogonSessionFlags &
(KERB_LOGON_LOCAL_ONLY | KERB_LOGON_DEFERRED)) )
{
Status = KerbGetOurDomainName( &OurDomainName );
ASSERT( NT_SUCCESS(Status) && L"KerbGenerateAuditForLogonUsingExplicitCreds: KerbGetOurDomainName failed" );
if (NT_SUCCESS(Status))
{
//
// find the cached ticket for the local machine from
// the ticket cache of the current logon session.
//
pTicketCacheEntry =
KerbLocateTicketCacheEntry(
&pCurrentUserLogonSession->PrimaryCredentials.ServerTicketCache,
KerbGlobalMitMachineServiceName,
&OurDomainName
);
if ( pTicketCacheEntry )
{
//
// Convert start time to the format we want.
//
KerbConvertLargeIntToGeneralizedTime(
&CurrentUserStartTime,
NULL,
&pTicketCacheEntry->StartTime
);
//
// Generate the logon GUID
//
Status = LsaIGetLogonGuid(
&pCurrentUserLogonSession->PrimaryCredentials.UserName,
&pCurrentUserLogonSession->PrimaryCredentials.DomainName,
(PBYTE) &CurrentUserStartTime,
sizeof(KERB_TIME),
&CurrentUserLogonGuid
);
if (NT_SUCCESS(Status))
{
pCurrentUserLogonGuid = &CurrentUserLogonGuid;
}
}
else
{
D_DebugLog((DEB_TRACE, "KerbGenerateAuditForLogonUsingExplicitCreds: could not locate ticket"));
}
}
KerbFreeString(&OurDomainName);
}
#if DBG
else
{
//
// KERB_LOGON_LOCAL_ONLY indicates a logon using non Kerberos package.
// Logon GUID is supported only by Kerberos therefore its generation
// is skipped.
//
if (pCurrentUserLogonSession->LogonSessionFlags & KERB_LOGON_LOCAL_ONLY)
{
D_DebugLog((DEB_TRACE,"KerbGenerateAuditForLogonUsingExplicitCreds: LogonSession %p has KERB_LOGON_LOCAL_ONLY\n", pCurrentUserLogonSession));
}
//
// KERB_LOGON_DEFERRED indicates that a logon occurred using
// cached credentials because kdc was not available. In this case,
// we will not have a ticket for local machine therefore generation of
// the logon GUID is skipped.
//
if (pCurrentUserLogonSession->LogonSessionFlags & KERB_LOGON_DEFERRED)
{
D_DebugLog((DEB_TRACE,"KerbGenerateAuditForLogonUsingExplicitCreds: LogonSession %p has KERB_LOGON_DEFERRED\n", pCurrentUserLogonSession));
}
}
#endif
//
// now generate the audit
//
Status = I_LsaIAuditLogonUsingExplicitCreds(
EVENTLOG_AUDIT_SUCCESS,
NULL, // no user sid
&pCurrentUserLogonSession->PrimaryCredentials.UserName,
&pCurrentUserLogonSession->PrimaryCredentials.DomainName,
&pCurrentUserLogonSession->LogonId,
pCurrentUserLogonGuid,
&pNewUserPrimaryCredentials->UserName,
&pNewUserPrimaryCredentials->DomainName,
pNewUserLogonGuid
);
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: KerbAuditLogon
//
// Synopsis: Generate a successful logon audit event
//
// Arguments: LogonStatus -- overall logon status
// LogonSubStatus -- sub-category within a failed logon status
// pEncryptedTicket -- ticket used
// pUserSid -- user's SID
// pWorkstationName -- logon workstation
// pLogonId -- logon LUID
//
// Returns: NTSTATUS code
//
// Notes: A new field (logon GUID) was added to this audit event.
// In order to send this new field to LSA, we had two options:
// 1) add new function (AuditLogonEx) to LSA dispatch table
// 2) define a private (LsaI) function to do the job
//
// option#2 was chosen because the logon GUID is a Kerberos only
// feature.
//
//--------------------------------------------------------------------------
NTSTATUS
KerbAuditLogon(
IN NTSTATUS LogonStatus,
IN NTSTATUS LogonSubStatus,
IN PKERB_ENCRYPTED_TICKET pEncryptedTicket,
IN PSID pUserSid,
IN PUNICODE_STRING pWorkstationName,
IN PLUID pLogonId
)
{
GUID LogonGuid = { 0 };
NTSTATUS Status = STATUS_SUCCESS;
//PKERB_TIME pStartTime;
UNICODE_STRING ClientRealm = { 0 };
UNICODE_STRING ClientName = { 0 };
KERBERR KerbErr = KDC_ERR_NONE;
ULONG NameType;
//
// convert kerb style names to UNICODE_STRINGs
//
KerbErr = KerbConvertRealmToUnicodeString(
&ClientRealm,
&pEncryptedTicket->client_realm );
if ( KerbErr == KDC_ERR_NONE )
{
KerbErr = KerbConvertPrincipalNameToString(
&ClientName,
&NameType,
&pEncryptedTicket->client_name
);
}
if ( KerbErr != KDC_ERR_NONE )
{
Status = KerbMapKerbError( KerbErr );
goto Cleanup;
}
//
// generate the logon GUID
//
Status = I_LsaIGetLogonGuid(
&ClientName,
&ClientRealm,
(PBYTE)&pEncryptedTicket->KERB_ENCRYPTED_TICKET_starttime,
sizeof(KERB_TIME),
&LogonGuid
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
//
// generate successful logon audit. use the special
// LsaIAuditKerberosLogon function so that we can pass in
// the generated unique logon guid
//
I_LsaIAuditKerberosLogon(
LogonStatus,
LogonSubStatus,
&ClientName,
&ClientRealm,
pWorkstationName,
pUserSid,
Network,
&KerberosSource,
pLogonId,
&LogonGuid
);
Cleanup:
if (ClientRealm.Buffer != NULL)
{
KerbFreeString( &ClientRealm );
}
if (ClientName.Buffer != NULL)
{
KerbFreeString( &ClientName );
}
if ( !NT_SUCCESS( Status ) )
{
D_DebugLog((DEB_ERROR,"KerbAuditLogon: failed: %x\n", Status ));
}
return Status;
}