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.
 
 
 
 
 
 

366 lines
11 KiB

//+-----------------------------------------------------------------------
//
// 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
// pTargetName -- name of the target server
//
// Returns: NTSTATUS code
//
// Notes: This event covers credentials obtained from credman
//
//--------------------------------------------------------------------------
NTSTATUS
KerbGenerateAuditForLogonUsingExplicitCreds(
IN PKERB_LOGON_SESSION pCurrentUserLogonSession,
IN PKERB_PRIMARY_CREDENTIAL pNewUserPrimaryCredentials,
IN LPGUID pNewUserLogonGuid,
IN PKERB_INTERNAL_NAME pTargetName
)
{
NTSTATUS Status = STATUS_SUCCESS;
GUID CurrentUserLogonGuid;
LPGUID pCurrentUserLogonGuid = NULL;
PKERB_TICKET_CACHE_ENTRY pTicketCacheEntry = NULL;
UNICODE_STRING OurDomainName = { 0 };
KERB_TIME CurrentUserStartTime = { 0 };
KERBERR KerbErr = KDC_ERR_NONE;
PUNICODE_STRING pTargetServerName = NULL;
PUNICODE_STRING pTargetFullName = NULL;
UNICODE_STRING TargetFullName = { 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"));
}
}
//
// ISSUE-2002/03/28-kumarp : this should be inside the if stmt
//
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
//
// convert pTargetName which is in kdc format to a UNICODE_STRING
//
KerbErr = KerbConvertKdcNameToString(
&TargetFullName,
pTargetName,
NULL
);
if ( KerbErr == KDC_ERR_NONE )
{
pTargetFullName = &TargetFullName;
}
else
{
pTargetFullName = NULL;
}
//
// extract the target computer name for known cases
//
if ( pTargetName->NameCount == 1 )
{
pTargetServerName = &pTargetName->Names[0];
}
else if ( pTargetName->NameCount >= 2 )
{
pTargetServerName = &pTargetName->Names[1];
}
else
{
pTargetServerName = NULL;
}
//
// now generate the audit
//
Status = I_LsaIAuditLogonUsingExplicitCreds(
EVENTLOG_AUDIT_SUCCESS,
&pCurrentUserLogonSession->LogonId,
pCurrentUserLogonGuid,
(HANDLE) (ULONG_PTR) GetCurrentProcessId(),
&pNewUserPrimaryCredentials->UserName,
&pNewUserPrimaryCredentials->DomainName,
pNewUserLogonGuid,
pTargetServerName,
pTargetFullName
);
if ( TargetFullName.Buffer != NULL )
{
MIDL_user_free( TargetFullName.Buffer );
}
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
// pTransittedServices -- list of transitted services
//
// 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_CONTEXT Context,
IN PUNICODE_STRING pWorkstationName,
IN PLUID pLogonId,
IN PLSA_ADT_STRING_LIST pTransittedServices
)
{
GUID LogonGuid = { 0 };
NTSTATUS Status = STATUS_SUCCESS;
KERB_TIME StartTime;
//
// Pull this eventually. I think we're OK, though.
//
if (Context == NULL)
{
DsysAssert(FALSE);
goto Cleanup;
}
KerbConvertLargeIntToGeneralizedTime(
&StartTime,
NULL,
&Context->StartTime
);
//
// generate the logon GUID
//
Status = I_LsaIGetLogonGuid(
&Context->ClientName,
&Context->ClientRealm,
(PBYTE) &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,
&Context->ClientName,
&Context->ClientRealm,
pWorkstationName,
Context->UserSid,
Network,
&KerberosSource,
pLogonId,
&LogonGuid,
pTransittedServices
);
Cleanup:
if ( !NT_SUCCESS( Status ) )
{
D_DebugLog((DEB_ERROR,"KerbAuditLogon: failed: %x\n", Status ));
}
return Status;
}