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.
 
 
 
 
 
 

3955 lines
97 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
adtevent.c
Abstract:
Functions that implement audits generated by LSA itself.
Author:
Scott Birrell (ScottBi) January 19, 1993
Environment:
Revision History:
--*/
#include <lsapch2.h>
#include "adtp.h"
#include "adtutil.h"
#include "adtdebug.h"
#include "msobjs.h"
//
// Forwards
//
NTSTATUS
LsapAdtGetDbAttributesChangeString(
IN LSAP_DB_ATTRIBUTE* OldAttributes,
IN LSAP_DB_ATTRIBUTE* NewAttributes,
IN ULONG AttributeCount,
OUT LPWSTR* AttributeChangeString
);
NTSTATUS
LsapAdtGenerateObjectOperationAuditEvent(
IN LSAPR_HANDLE ObjectHandle,
IN USHORT AuditEventType,
IN OBJECT_OPERATION_TYPE OperationType
)
/*++
Routine Description:
Generates an audit entry when an operation on the object
represented by ObjectHandle succeeds/fails and if this type of
auditing is enabled.
Arguments:
ObjectHandle - Handle of the object being accessed
AuditEventType - The type of audit event to be generated.
EVENTLOG_AUDIT_SUCCESS or EVENTLOG_AUDIT_FAILURE
OperationType - Type of operation performed on the object
represented by ObjectHandle.
Return Value:
NTSTATUS - Standard Nt Result Code
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
SE_ADT_PARAMETER_ARRAY AuditParameters;
LUID ClientAuthenticationId;
PTOKEN_USER TokenUserInformation=NULL;
UNICODE_STRING OperationTypeName;
LSAP_DB_HANDLE InternalHandle;
UNICODE_STRING ObjectName;
LUID SystemAuthId = SYSTEM_LUID;
BOOLEAN bAudit;
static LPCWSTR ObjectOperationNames[ObjectOperationDummyLast] = {
L"None",
L"Query"
};
LsapEnterFunc("LsapAdtGenerateObjectAcessAuditEvent");
InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
Status = LsapQueryClientInfo(
&TokenUserInformation,
&ClientAuthenticationId
);
if ( !NT_SUCCESS( Status )) {
goto Cleanup;
}
if ( RtlEqualLuid( &ClientAuthenticationId, &SystemAuthId )) {
//
// do not audit secret queries by the system
//
goto Cleanup;
}
Status = LsapAdtAuditingEnabledByLogonId(
AuditCategoryObjectAccess,
&ClientAuthenticationId,
AuditEventType,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit)
{
goto Cleanup;
}
//
// LsarQuerySecret sometimes passes us a secret whose name will
// be rejected by ElfReportEventW because the length parameter
// includes the terminating NULL.
//
// For example,
// name.Buffer = "foo\0"
// name.Length = 8
// name.MaximumLength = 8
//
// We cannot change the input param or change the LSA code to
// not do this, therfore we make a local copy, fix it
// and use that instead
//
ObjectName = InternalHandle->PhysicalNameU;
ObjectName.Length = (USHORT) LsapSafeWcslen( ObjectName.Buffer,
ObjectName.MaximumLength );
//
// Build an audit parameters structure.
//
RtlInitUnicodeString( &OperationTypeName, ObjectOperationNames[OperationType] );
Status =
LsapAdtInitParametersArray(
&AuditParameters,
SE_CATEGID_OBJECT_ACCESS,
SE_AUDITID_OBJECT_OPERATION,
AuditEventType,
13, // there are 13 params to init
//
// User Sid
//
SeAdtParmTypeSid, TokenUserInformation->User.Sid,
//
// Subsystem name
//
SeAdtParmTypeString, &LsapSubsystemName,
//
// Object server
//
SeAdtParmTypeString, &LsapLsaName,
//
// Operation Type
//
SeAdtParmTypeString, &OperationTypeName,
//
// Object Type : index of this is 4, used later
//
SeAdtParmTypeString, &LsapDbObjectTypeNames[InternalHandle->
ObjectTypeId],
//
// Object Name
//
SeAdtParmTypeString, &ObjectName,
//
// Object Handle ID
//
SeAdtParmTypePtr, ObjectHandle,
//
// Primary Authentication information
//
SeAdtParmTypeLogonId, LsapSystemLogonId,
//
// Clients's Authentication information
//
SeAdtParmTypeLogonId, ClientAuthenticationId,
//
// Requested access : 4 is the index of ObjectType parameter
//
SeAdtParmTypeAccessMask, InternalHandle->RequestedAccess, 4,
//
// there are no object properties (object-type list)
//
SeAdtParmTypeNone,
//
// no additional information
//
SeAdtParmTypeNone,
//
// Access Mask (hex)
//
SeAdtParmTypeHexUlong, InternalHandle->RequestedAccess
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
( VOID ) LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (TokenUserInformation != NULL)
{
LsapFreeLsaHeap( TokenUserInformation );
}
if (!NT_SUCCESS(Status)) {
LsapAuditFailed( Status );
}
LsapExitFunc("LsapAdtGenerateObjectAcessAuditEvent", Status);
return Status;
}
NTSTATUS
LsapAdtGenerateLsaAuditEvent(
IN LSAPR_HANDLE ObjectHandle,
IN ULONG AuditEventCategory,
IN ULONG AuditEventId,
IN PPRIVILEGE_SET Privileges,
IN ULONG SidCount,
IN PSID *Sids OPTIONAL,
IN ULONG UnicodeStringCount,
IN PUNICODE_STRING UnicodeStrings OPTIONAL,
IN PLSARM_POLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo OPTIONAL
)
/*++
Routine Description:
This function generates an Lsa-originated Audit Event. Audit Events
of this kind are generated as a result of Local Security Policy changes
such as assigning/removing user rights to an account.
Arguments:
ObjectHandle - Specifies the handle of an object in the Lsa Policy
Database. For global changes to policy, a handle to the
Lsa Policy object is passed.
AuditEventCategory - Specifies the Id of the Audit Event Category
to which this Audit Event belongs.
AuditEventId - Specifies the Id of the Audit Event being generated.
Privileges - set of privileges to be recorded
SidCount - Count of Sids being passed via the Sids parameter. If no
Sids are passed, this parameter must be set to 0.
Sids - Pointer to array of SidCount Sids. If 0 is passed for the
SidCount parameter, this parameter is ignored and NULL may be
specified.
UnicodeStringCount - Count of Unicode Strings being passed via the
UnicodeStrings parameter. If no Unicode Strings are passed, this
parameter must be set to 0.
UnicodeStrings - Pointer to array of UnicodeStringCount strings. If 0 is
passed for the SidCount parameter, this parameter is ignored and NULL
may be specified.
PolicyAuditEventsInfo - Pointer to Auditing Events information structure
containing the AuditingMode and the array of Policy Audit Event
Information entries. This parameter must be non-NULL if and only if
the AuditEventCategory parameter is SE_AUDIT_POLICY_CHANGE.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
LUID ClientAuthenticationId;
PTOKEN_USER TokenUserInformation = NULL;
PSID ClientSid;
BOOLEAN bAudit;
UNREFERENCED_PARAMETER( ObjectHandle );
if (Privileges && !IsValidPrivilegeCount(Privileges->PrivilegeCount)) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
Status = LsapQueryClientInfo(
&TokenUserInformation,
&ClientAuthenticationId
);
if ( !NT_SUCCESS( Status )) {
goto Cleanup;
}
ClientSid = TokenUserInformation->User.Sid;
if (AuditEventId != SE_AUDITID_POLICY_CHANGE) {
Status = LsapAdtAuditingEnabledByLogonId(
LsapAdtEventTypeFromCategoryId(AuditEventCategory),
&ClientAuthenticationId,
EVENTLOG_AUDIT_SUCCESS,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit) {
goto Cleanup;
}
}
Status = LsapAdtGenerateLsaAuditEventWithClientSid( AuditEventCategory,
AuditEventId,
ClientSid,
ClientAuthenticationId,
Privileges,
SidCount,
Sids,
UnicodeStringCount,
UnicodeStrings,
PolicyAuditEventsInfo );
Cleanup:
if (TokenUserInformation != NULL)
{
LsapFreeLsaHeap( TokenUserInformation );
}
if ( !NT_SUCCESS( Status )) {
LsapAuditFailed( Status );
}
return(Status);
}
NTSTATUS
LsapAdtGenerateLsaAuditEventWithClientSid(
IN ULONG AuditEventCategory,
IN ULONG AuditEventId,
IN PSID ClientSid,
IN LUID ClientAuthenticationId,
IN PPRIVILEGE_SET Privileges,
IN ULONG SidCount,
IN PSID *Sids OPTIONAL,
IN ULONG UnicodeStringCount,
IN PUNICODE_STRING UnicodeStrings OPTIONAL,
IN PLSARM_POLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo OPTIONAL
)
/*++
Routine Description:
This function generates an Lsa-originated Audit Event. Audit Events
of this kind are generated as a result of Local Security Policy changes
such as assigning/removing user rights to an account.
The decision to generate these audits is made in LsapAdtGenerateLsaAuditEvent.
Arguments:
ObjectHandle - Specifies the handle of an object in the Lsa Policy
Database. For global changes to policy, a handle to the
Lsa Policy object is passed.
AuditEventCategory - Specifies the Id of the Audit Event Category
to which this Audit Event belongs.
AuditEventId - Specifies the Id of the Audit Event being generated.
Privileges - set of privileges to be recorded
SidCount - Count of Sids being passed via the Sids parameter. If no
Sids are passed, this parameter must be set to 0.
Sids - Pointer to array of SidCount Sids. If 0 is passed for the
SidCount parameter, this parameter is ignored and NULL may be
specified.
UnicodeStringCount - Count of Unicode Strings being passed via the
UnicodeStrings parameter. If no Unicode Strings are passed, this
parameter must be set to 0.
UnicodeStrings - Pointer to array of UnicodeStringCount strings. If 0 is
passed for the SidCount parameter, this parameter is ignored and NULL
may be specified.
PolicyAuditEventsInfo - Pointer to Auditing Events information structure
containing the AuditingMode and the array of Policy Audit Event
Information entries. This parameter must be non-NULL if and only if
the AuditEventCategory parameter is SE_AUDIT_POLICY_CHANGE.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING NullString = {0};
if (NULL == UnicodeStrings)
{
UnicodeStrings = &NullString;
}
UNREFERENCED_PARAMETER( UnicodeStringCount );
UNREFERENCED_PARAMETER( SidCount );
switch ( AuditEventCategory ) {
case SE_CATEGID_POLICY_CHANGE:
{
switch ( AuditEventId ) {
default:
DsysAssertMsg(FALSE, "LsapAdtGenerateLsaAuditEventWithClientSid: invalid AuditEventId");
break;
case SE_AUDITID_POLICY_CHANGE:
{
LsapAdtPolicyChange(
(USHORT)AuditEventCategory,
AuditEventId,
EVENTLOG_AUDIT_SUCCESS,
ClientSid,
ClientAuthenticationId,
PolicyAuditEventsInfo
);
break;
}
case SE_AUDITID_USER_RIGHT_ASSIGNED:
case SE_AUDITID_USER_RIGHT_REMOVED:
{
DsysAssertMsg( SidCount == 1,
"LsapAdtGenerateLsaAuditEventWithClientSid" );
LsapAdtUserRightAssigned(
(USHORT)AuditEventCategory,
AuditEventId,
EVENTLOG_AUDIT_SUCCESS,
ClientSid,
ClientAuthenticationId,
Sids[0],
Privileges
);
break;
}
}
break;
}
default:
{
DsysAssertMsg( FALSE, "LsapAdtGenerateLsaAuditEventWithClientSid: unsupported audit category" );
return( STATUS_SUCCESS );
}
}
return(Status);
}
VOID
LsapAdtUserRightAssigned(
IN USHORT EventCategory,
IN ULONG EventID,
IN USHORT EventType,
IN PSID ClientSid,
IN LUID CallerAuthenticationId,
IN PSID TargetSid,
IN PPRIVILEGE_SET Privileges
)
/*++
Routine Description:
Generates an audit for a user right being either assigned or removed.
The decision to generate this audit is made in LsapAdtGenerateLsaAuditEvent.
Arguments:
ISSUE-2002/03/11-kumarp : add desc
Return Value:
None.
--*/
{
SE_ADT_PARAMETER_ARRAY AuditParameters;
//
// if no privileges are being assigned/removed, dont generate the audit
//
if (!(Privileges && Privileges->PrivilegeCount))
{
return;
}
//
// Build an audit parameters structure.
//
RtlZeroMemory (
(PVOID) &AuditParameters,
sizeof( AuditParameters )
);
AuditParameters.CategoryId = EventCategory;
AuditParameters.AuditId = EventID;
AuditParameters.Type = EventType;
AuditParameters.ParameterCount = 0;
//
// User Sid
//
LsapSetParmTypeSid( AuditParameters, AuditParameters.ParameterCount, ClientSid );
AuditParameters.ParameterCount++;
//
// Subsystem name (if available)
//
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LsapSubsystemName );
AuditParameters.ParameterCount++;
//
// Rights
//
LsapSetParmTypePrivileges( AuditParameters, AuditParameters.ParameterCount, Privileges );
AuditParameters.ParameterCount++;
//
// Target Sid
//
LsapSetParmTypeSid( AuditParameters, AuditParameters.ParameterCount, TargetSid );
AuditParameters.ParameterCount++;
//
// Caller's Authentication information
//
LsapSetParmTypeLogonId( AuditParameters, AuditParameters.ParameterCount, CallerAuthenticationId );
AuditParameters.ParameterCount++;
( VOID ) LsapAdtWriteLog( &AuditParameters );
return;
}
VOID
LsapAdtGenerateLsaAuditSystemAccessChange(
IN USHORT EventCategory,
IN ULONG EventID,
IN USHORT EventType,
IN PSID ClientSid,
IN LUID CallerAuthenticationId,
IN PSID TargetSid,
IN PCWSTR szSystemAccess
)
/*++
Routine Description:
Generates an audit for System Security Access changes.
The decision to generate this audit is made in LsapSetSystemAccessAccount.
Arguments:
EventCategory - The category of this event
EventID - specific ID of event
EventType - success or failure
ClientSid - sid of client
CallerAuthenticationID - Logon ID of caller
TargetSid - receives access change
szSystemAccess - string describing which access changed
Return Value:
None.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
SE_ADT_PARAMETER_ARRAY AuditParameters;
UNICODE_STRING SystemAccessString;
//
// Build an audit parameters structure.
//
RtlZeroMemory (
(PVOID) &AuditParameters,
sizeof( AuditParameters )
);
RtlInitUnicodeString( &SystemAccessString, szSystemAccess );
Status =
LsapAdtInitParametersArray( &AuditParameters,
EventCategory,
EventID,
EventType,
5,
SeAdtParmTypeSid, ClientSid,
SeAdtParmTypeString, &LsapSubsystemName,
SeAdtParmTypeLogonId, CallerAuthenticationId,
SeAdtParmTypeString, &SystemAccessString,
SeAdtParmTypeSid, TargetSid
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
(VOID) LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (!NT_SUCCESS(Status))
{
LsapAuditFailed( Status );
}
}
NTSTATUS
LsapAdtTrustedDomainAdd(
IN USHORT EventType,
IN PUNICODE_STRING pName,
IN PSID pSid,
IN ULONG Type,
IN ULONG Direction,
IN ULONG Attributes
)
/*++
Routine Description:
Generate an audit event when a trusted domain object (TDO) is created.
Arguments:
EventType - EVENTLOG_AUDIT_SUCCESS or EVENTLOG_AUDIT_FAILURE
pName - name of the domain
pSid - domain SID
Type - TDO type
Direction - TDO direction
Attributes - TDO attributes
Return Value:
NTSTATUS - Standard Nt Result Code
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
LUID ClientAuthenticationId;
PTOKEN_USER TokenUserInformation=NULL;
SE_ADT_PARAMETER_ARRAY AuditParameters = { 0 };
BOOLEAN bAudit = FALSE;
Status = LsapQueryClientInfo( &TokenUserInformation, &ClientAuthenticationId );
if ( !NT_SUCCESS( Status ))
{
goto Cleanup;
}
Status = LsapAdtAuditingEnabledByLogonId(
AuditCategoryPolicyChange,
&ClientAuthenticationId,
EventType,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit)
{
goto Cleanup;
}
//
// Build an audit parameters structure.
//
Status =
LsapAdtInitParametersArray(
&AuditParameters,
SE_CATEGID_POLICY_CHANGE,
SE_AUDITID_TRUSTED_DOMAIN_ADD,
EventType,
9, // there are 9 params to init
//
// User Sid
//
SeAdtParmTypeSid, TokenUserInformation->User.Sid,
//
// Subsystem name (if available)
//
SeAdtParmTypeString, &LsapSubsystemName,
//
// domain name
//
SeAdtParmTypeString, pName,
//
// domain id
//
SeAdtParmTypeSid, pSid,
//
// client auth-id
//
SeAdtParmTypeLogonId, ClientAuthenticationId,
//
// TDO type
//
SeAdtParmTypeUlong, Type,
//
// TDO direction
//
SeAdtParmTypeUlong, Direction,
//
// TDO attributes
//
SeAdtParmTypeUlong, Attributes,
//
// TDO: attribute quarantined spelled out
//
SeAdtParmTypeMessage, (Attributes & TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ? SE_ADT_MSG_ENABLED : SE_ADT_MSG_DISABLED
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (TokenUserInformation != NULL)
{
LsapFreeLsaHeap( TokenUserInformation );
}
if (!NT_SUCCESS(Status))
{
LsapAuditFailed( Status );
}
return Status;
}
NTSTATUS
LsapAdtTrustedDomainRem(
IN USHORT EventType,
IN PUNICODE_STRING pName,
IN PSID pSid,
IN PSID pClientSid,
IN PLUID pClientAuthId
)
/*++
Routine Description:
Generate an audit event when a trusted domain object (TDO) is deleted.
Arguments:
EventType - EVENTLOG_AUDIT_SUCCESS or EVENTLOG_AUDIT_FAILURE
pName - name of the domain
pSid - domain SID
pClientSid - SID of the client who deleted the TDO
if NULL, it is determined from the thread token
pClientAuthId- auth-id of the client who deleted the TDO
if NULL, it is determined from the thread token
Return Value:
NTSTATUS - Standard Nt Result Code
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
LUID ClientAuthenticationId;
PTOKEN_USER TokenUserInformation=NULL;
SE_ADT_PARAMETER_ARRAY AuditParameters = { 0 };
BOOLEAN bAudit = FALSE;
if ( pClientSid == NULL )
{
DsysAssertMsg( pClientAuthId == NULL, "LsapAdtTrustedDomainRem" );
Status = LsapQueryClientInfo( &TokenUserInformation,
&ClientAuthenticationId );
if ( !NT_SUCCESS( Status ))
{
goto Cleanup;
}
pClientSid = TokenUserInformation->User.Sid;
pClientAuthId = &ClientAuthenticationId;
}
#if DBG
else
{
DsysAssertMsg( pClientAuthId != NULL, "LsapAdtTrustedDomainRem" );
}
#endif
Status = LsapAdtAuditingEnabledByLogonId(
AuditCategoryPolicyChange,
pClientAuthId,
EventType,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit)
{
goto Cleanup;
}
//
// Build an audit parameters structure.
//
Status =
LsapAdtInitParametersArray(
&AuditParameters,
SE_CATEGID_POLICY_CHANGE,
SE_AUDITID_TRUSTED_DOMAIN_REM,
EventType,
5, // there are 5 params to init
//
// User Sid
//
SeAdtParmTypeSid, pClientSid,
//
// Subsystem name (if available)
//
SeAdtParmTypeString, &LsapSubsystemName,
//
// domain name
//
SeAdtParmTypeString, pName,
//
// domain id (SID of the root domain)
//
SeAdtParmTypeSid, pSid,
//
// client auth-id
//
SeAdtParmTypeLogonId, *pClientAuthId
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (TokenUserInformation != NULL)
{
LsapFreeLsaHeap( TokenUserInformation );
}
if (!NT_SUCCESS(Status))
{
LsapAuditFailed( Status );
}
return Status;
}
NTSTATUS
LsapAdtTrustedDomainMod(
IN USHORT EventType,
IN PSID pDomainSid,
IN PUNICODE_STRING pOldName,
IN ULONG OldType,
IN ULONG OldDirection,
IN ULONG OldAttributes,
IN PUNICODE_STRING pNewName,
IN ULONG NewType,
IN ULONG NewDirection,
IN ULONG NewAttributes
)
/*++
Routine Description:
Generate an audit event when a trusted domain object (TDO) is modified.
the unmodified fields are represented by a '-' in the audit log.
Arguments:
EventType - EVENTLOG_AUDIT_SUCCESS or EVENTLOG_AUDIT_FAILURE
pOldName - old name of the domain
pOldSid - old domain SID
OldType - old TDO type
OldDirection - old TDO direction
OldAttributes - old TDO attributes
pNewName - new name of the domain
pNewSid - new domain SID
NewType - new TDO type
NewDirection - new TDO direction
NewAttributes - new TDO attributes
Return Value:
NTSTATUS - Standard Nt Result Code
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
LUID ClientAuthenticationId;
PTOKEN_USER TokenUserInformation=NULL;
SE_ADT_PARAMETER_ARRAY AuditParameters = { 0 };
BOOLEAN bAudit = FALSE;
Status = LsapQueryClientInfo( &TokenUserInformation, &ClientAuthenticationId );
if ( !NT_SUCCESS( Status ))
{
goto Cleanup;
}
//
// if auditing is not enabled, return asap
//
Status = LsapAdtAuditingEnabledByLogonId(
AuditCategoryPolicyChange,
&ClientAuthenticationId,
EventType,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit)
{
goto Cleanup;
}
AuditParameters.CategoryId = SE_CATEGID_POLICY_CHANGE;
AuditParameters.AuditId = SE_AUDITID_TRUSTED_DOMAIN_MOD;
AuditParameters.Type = EventType;
AuditParameters.ParameterCount = 9;
//
// User Sid
//
LsapSetParmTypeSid( AuditParameters, 0, TokenUserInformation->User.Sid );
//
// Subsystem name (if available)
//
LsapSetParmTypeString( AuditParameters, 1, &LsapSubsystemName );
//
// for all subsequent fields (except the domain SID),
// output a value only if it changed.
//
//
// domain name
//
if ( pOldName && pNewName &&
!RtlEqualUnicodeString( pOldName, pNewName, TRUE ) )
{
LsapSetParmTypeString( AuditParameters, 2, pNewName );
}
//
// domain id
//
LsapSetParmTypeSid( AuditParameters, 3, pDomainSid );
//
// client auth-id
//
LsapSetParmTypeLogonId( AuditParameters, 4, ClientAuthenticationId );
//
// TDO type
//
if ( OldType != NewType )
{
LsapSetParmTypeUlong( AuditParameters, 5, NewType );
}
//
// TDO direction
//
if ( OldDirection != NewDirection )
{
LsapSetParmTypeUlong( AuditParameters, 6, NewDirection );
}
//
// TDO attributes
//
if ( OldAttributes != NewAttributes )
{
LsapSetParmTypeUlong( AuditParameters, 7, NewAttributes );
}
//
// TDO attributes
//
if ( OldAttributes != NewAttributes )
{
LsapSetParmTypeMessage( AuditParameters, 8, (NewAttributes & TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ? SE_ADT_MSG_ENABLED : SE_ADT_MSG_DISABLED );
}
Status = LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (TokenUserInformation != NULL)
{
LsapFreeLsaHeap( TokenUserInformation );
}
if (!NT_SUCCESS(Status))
{
LsapAuditFailed( Status );
}
return Status;
}
NTSTATUS
LsapAdtTrustedForestNamespaceCollision(
IN LSA_FOREST_TRUST_COLLISION_RECORD_TYPE CollisionTargetType,
IN PUNICODE_STRING pCollisionTargetName,
IN PUNICODE_STRING pForestRootDomainName,
IN PUNICODE_STRING pTopLevelName,
IN PUNICODE_STRING pDnsName,
IN PUNICODE_STRING pNetbiosName,
IN PSID pSid,
IN ULONG NewFlags
)
/*++
Routine Description:
This function generates the audit event that represents
a namespace element collision.
Arguments:
CollisionTargetType - type of the collision target
CollisionTdo : indicates a collision with a namespace element of
another forest
CollisionXref : indicates a collision with a domain in our forest
pCollisionTargetName -
name of the collision target (TDO name or Xref name)
pForestRootDomainName - name of other forest
pTopLevelName - top level name (NULL == not in conflict)
pDnsName - DNS domain name (this is NULL if TLN is non-NULL)
pNetbiosName - NetBIOS name (NULL == not in conflict)
pSid - SID of domain (NULL == not in conflict)
NewFlags - the new value of flags
Return Value:
NTSTATUS - Standard Nt Result Code
Notes:
This event is generated only in the success case.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
SE_ADT_PARAMETER_ARRAY AuditParameters = { 0 };
BOOLEAN bAudit;
#if DBG
HANDLE hToken;
#endif
DsysAssert(( CollisionTargetType == CollisionTdo ) ||
( CollisionTargetType == CollisionXref));
DsysAssert( pCollisionTargetName != NULL );
DsysAssert( pForestRootDomainName != NULL );
#if DBG
if ( pTopLevelName )
{
DsysAssert( pDnsName == NULL );
DsysAssert( pNetbiosName == NULL );
DsysAssert( pSid == NULL );
}
else
{
DsysAssert( pDnsName != NULL );
if ( pNetbiosName != NULL )
{
DsysAssert( pSid == NULL );
}
if ( pSid != NULL )
{
DsysAssert( pNetbiosName == NULL );
}
}
#endif
//
// if auditing is not enabled, return asap
//
Status = LsapAdtAuditingEnabledBySid(
AuditCategoryPolicyChange,
LsapLocalSystemSid,
EVENTLOG_AUDIT_SUCCESS,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit)
{
goto Cleanup;
}
#if DBG
//
// make sure that this is called in the system context
//
Status = NtOpenThreadToken( NtCurrentThread(), TOKEN_QUERY, TRUE, &hToken );
DsysAssertMsg( Status == STATUS_NO_TOKEN, "LsapAdtTrustedForestNamespaceCollision" );
if ( NT_SUCCESS(Status) )
{
NtClose( hToken );
}
else
{
Status = STATUS_SUCCESS;
}
#endif
//
// Build an audit parameters structure.
//
Status =
LsapAdtInitParametersArray(
&AuditParameters,
SE_CATEGID_POLICY_CHANGE,
SE_AUDITID_NAMESPACE_COLLISION,
EVENTLOG_AUDIT_SUCCESS,
//
// number of params to follow
//
10,
//
// User Sid
//
SeAdtParmTypeSid, LsapLocalSystemSid,
//
// Subsystem name (if available)
//
SeAdtParmTypeString, &LsapSubsystemName,
//
// collision target type
//
// 0 == CollisionTdo
// 1 == CollisionXref
//
SeAdtParmTypeUlong, CollisionTargetType,
//
// collision target name
//
// name of a TDO or cross-ref
//
SeAdtParmTypeString, pCollisionTargetName,
//
// Name of forest involved in the collision
//
SeAdtParmTypeString, pForestRootDomainName,
//
// top level name
//
SeAdtParmTypeString, pTopLevelName,
//
// DNS name
//
SeAdtParmTypeString, pDnsName,
//
// NetBIOS name
//
SeAdtParmTypeString, pNetbiosName,
//
// SID
//
SeAdtParmTypeSid, pSid,
//
// new flags value
//
SeAdtParmTypeUlong, NewFlags
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (!NT_SUCCESS(Status))
{
LsapAuditFailed( Status );
}
return Status;
}
NTSTATUS
LsapAdtTrustedForestInfoEntryAddRemHelper(
IN ULONG EventId,
IN USHORT EventType,
IN PUNICODE_STRING ForestName,
IN PSID pForestRootDomainSid,
IN PLUID pOperationId,
IN LSA_FOREST_TRUST_RECORD_TYPE EntryType,
IN ULONG Flags,
IN PUNICODE_STRING TopLevelName,
IN PUNICODE_STRING DnsName,
IN PUNICODE_STRING NetbiosName,
IN PSID pSid
)
/*++
Routine Description:
Helper function for generating audit event when a namespace
element has been added to / removed from forest trust info.
If multiple entries get added, deleted or modified
in a single update of the forest trust information, all the generated
audit events will have a single unique identifier called OperationID.
This allows one to determine that the multiple generated audits are
the result of a single operation.
Arguments:
EventId - SE_AUDITID_TRUSTED_FOREST_INFO_ENTRY_ADD/REM
EventType - EVENTLOG_AUDIT_SUCCESS or EVENTLOG_AUDIT_FAILURE
ForestName - name of the forest
pForestRootDomainSid - SID of the forest
pOperationId - operation id (see description above)
EntryType - type of entry ( TLN | TLN excl. | domain info )
Flags - flags associated with the entry ( see ntlsa.h )
TopLevelName - TopLevel name
DnsName - Dns name
NetbiosName - Netbios name
pSid - domain sid
Return Value:
NTSTATUS - Standard Nt Result Code
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
LUID ClientAuthenticationId;
PTOKEN_USER TokenUserInformation=NULL;
SE_ADT_PARAMETER_ARRAY AuditParameters = { 0 };
BOOLEAN bAudit;
Status = LsapQueryClientInfo( &TokenUserInformation, &ClientAuthenticationId );
if ( !NT_SUCCESS( Status ))
{
goto Cleanup;
}
//
// if auditing is not enabled, return asap
//
Status = LsapAdtAuditingEnabledByLogonId(
AuditCategoryPolicyChange,
&ClientAuthenticationId,
EventType,
&bAudit);
if (!NT_SUCCESS(Status) || !bAudit)
{
goto Cleanup;
}
//
// Build an audit parameters structure.
//
Status =
LsapAdtInitParametersArray(
&AuditParameters,
SE_CATEGID_POLICY_CHANGE,
EventId,
EventType,
//
// number of params to follow
//
13,
//
// User Sid
//
SeAdtParmTypeSid, TokenUserInformation->User.Sid,
//
// Subsystem name (if available)
//
SeAdtParmTypeString, &LsapSubsystemName,
//
// Forest name
//
SeAdtParmTypeString, ForestName,
//
// Forest SID
//
SeAdtParmTypeSid, pForestRootDomainSid,
//
// Operation ID
//
SeAdtParmTypeUlong, pOperationId->HighPart,
SeAdtParmTypeUlong, pOperationId->LowPart,
//
// Entry Type
//
SeAdtParmTypeUlong, EntryType,
//
// Flags
//
SeAdtParmTypeUlong, Flags,
//
// top level name
//
SeAdtParmTypeString, TopLevelName,
//
// DNS domain name
//
SeAdtParmTypeString, DnsName,
//
// NetBIOS domain name
//
SeAdtParmTypeString, NetbiosName,
//
// domain SID
//
SeAdtParmTypeSid, pSid,
//
// user info
//
SeAdtParmTypeLogonId, ClientAuthenticationId
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (TokenUserInformation != NULL)
{
LsapFreeLsaHeap( TokenUserInformation );
}
if (!NT_SUCCESS(Status))
{
LsapAuditFailed( Status );
}
return Status;
}
NTSTATUS
LsapAdtTrustedForestInfoEntryAdd(
IN PUNICODE_STRING pForestRootDomainName,
IN PSID pForestRootDomainSid,
IN PLUID pOperationId,
IN LSA_FOREST_TRUST_RECORD_TYPE EntryType,
IN ULONG Flags,
IN PUNICODE_STRING TopLevelName,
IN PUNICODE_STRING DnsName,
IN PUNICODE_STRING NetbiosName,
IN PSID pSid
)
{
return LsapAdtTrustedForestInfoEntryAddRemHelper(
SE_AUDITID_TRUSTED_FOREST_INFO_ENTRY_ADD,
EVENTLOG_AUDIT_SUCCESS,
pForestRootDomainName,
pForestRootDomainSid,
pOperationId,
EntryType,
Flags,
TopLevelName,
DnsName,
NetbiosName,
pSid
);
}
NTSTATUS
LsapAdtTrustedForestInfoEntryRem(
IN PUNICODE_STRING pForestRootDomainName,
IN PSID pForestRootDomainSid,
IN PLUID pOperationId,
IN LSA_FOREST_TRUST_RECORD_TYPE EntryType,
IN ULONG Flags,
IN PUNICODE_STRING TopLevelName,
IN PUNICODE_STRING DnsName,
IN PUNICODE_STRING NetbiosName,
IN PSID pSid
)
{
return LsapAdtTrustedForestInfoEntryAddRemHelper(
SE_AUDITID_TRUSTED_FOREST_INFO_ENTRY_REM,
EVENTLOG_AUDIT_SUCCESS,
pForestRootDomainName,
pForestRootDomainSid,
pOperationId,
EntryType,
Flags,
TopLevelName,
DnsName,
NetbiosName,
pSid
);
}
NTSTATUS
LsapAdtTrustedForestInfoEntryMod(
IN PUNICODE_STRING pForestRootDomainName,
IN PSID pForestRootDomainSid,
IN PLUID pOperationId,
IN LSA_FOREST_TRUST_RECORD_TYPE EntryType,
IN ULONG OldFlags,
IN PUNICODE_STRING pOldTopLevelName,
IN PUNICODE_STRING pOldDnsName,
IN PUNICODE_STRING pOldNetbiosName,
IN PSID pOldSid,
IN ULONG NewFlags,
IN PUNICODE_STRING pNewTopLevelName,
IN PUNICODE_STRING pNewDnsName,
IN PUNICODE_STRING pNewNetbiosName,
IN PSID pNewSid
)
/*++
Routine Description:
Helper function for generating audit event when a namespace
element in forest trust info has been modified.
If multiple entries get added, deleted or modified
in a single update of the forest trust information, all the generated
audit events will have a single unique identifier called OperationID.
This allows one to determine that the multiple generated audits are
the result of a single operation.
Arguments:
EventType - EVENTLOG_AUDIT_SUCCESS or EVENTLOG_AUDIT_FAILURE
ForestName - name of the forest
pForestRootDomainSid - SID of the forest
pOperationId - operation id (see description above)
EntryType - type of entry ( TLN | TLN excl. | domain info )
OldFlags - old flags associated with the entry ( see ntlsa.h )
pOldTopLevelName - old TopLevel name
pOldDnsName - old Dns name
pOldNetbiosName - old Netbios name
pOldSid - old domain sid
NewFlags - new flags associated with the entry ( see ntlsa.h )
pNewTopLevelName - new TopLevel name
pNewDnsName - new Dns name
pNewNetbiosName - new Netbios name
pNewSid - new domain sid
Return Value:
NTSTATUS - Standard Nt Result Code
Notes:
The unmodified fields are represented by a '-' in the audit log.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
LUID ClientAuthenticationId;
PTOKEN_USER TokenUserInformation=NULL;
SE_ADT_PARAMETER_ARRAY AuditParameters = { 0 };
BOOLEAN bAudit;
Status = LsapQueryClientInfo( &TokenUserInformation, &ClientAuthenticationId );
if ( !NT_SUCCESS( Status ))
{
goto Cleanup;
}
//
// if auditing is not enabled, return asap
//
Status = LsapAdtAuditingEnabledByLogonId(
AuditCategoryPolicyChange,
&ClientAuthenticationId,
EVENTLOG_AUDIT_SUCCESS,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit)
{
goto Cleanup;
}
AuditParameters.CategoryId = SE_CATEGID_POLICY_CHANGE;
AuditParameters.AuditId = SE_AUDITID_TRUSTED_FOREST_INFO_ENTRY_MOD;
AuditParameters.Type = EVENTLOG_AUDIT_SUCCESS;
AuditParameters.ParameterCount = 13;
//
// User Sid
//
LsapSetParmTypeSid( AuditParameters, 0, TokenUserInformation->User.Sid );
//
// Subsystem name (if available)
//
LsapSetParmTypeString( AuditParameters, 1, &LsapSubsystemName );
//
// forest name
//
LsapSetParmTypeString( AuditParameters, 2, pForestRootDomainName );
//
// forest id (SID of the root domain)
//
LsapSetParmTypeSid( AuditParameters, 3, pForestRootDomainSid );
//
// Operation ID
//
LsapSetParmTypeUlong( AuditParameters, 4, pOperationId->HighPart );
LsapSetParmTypeUlong( AuditParameters, 5, pOperationId->LowPart );
//
// entry type
//
LsapSetParmTypeUlong( AuditParameters, 6, EntryType );
//
// for all subsequent types, output a value only if it changed.
//
//
// Flags
//
if ( OldFlags != NewFlags )
{
LsapSetParmTypeUlong( AuditParameters, 7, NewFlags );
}
//
// top level name
//
if ( pOldTopLevelName && pNewTopLevelName &&
!RtlEqualUnicodeString( pOldTopLevelName, pNewTopLevelName, TRUE ) )
{
LsapSetParmTypeString( AuditParameters, 8, pNewTopLevelName );
}
//
// DNS domain name
//
if ( pOldDnsName && pNewDnsName &&
!RtlEqualUnicodeString( pOldDnsName, pNewDnsName, TRUE ) )
{
LsapSetParmTypeString( AuditParameters, 9, pNewDnsName );
}
//
// NetBIOS domain name
//
if ( pOldNetbiosName && pNewNetbiosName &&
!RtlEqualUnicodeString( pOldNetbiosName, pNewNetbiosName, TRUE ) )
{
LsapSetParmTypeString( AuditParameters, 10, pNewNetbiosName );
}
//
// domain SID
//
if ( pOldSid && pNewSid && !RtlEqualSid( pOldSid, pNewSid ) )
{
LsapSetParmTypeSid( AuditParameters, 11, pNewSid );
}
//
// client auth-id
//
LsapSetParmTypeLogonId( AuditParameters, 12, ClientAuthenticationId );
Status = LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (TokenUserInformation != NULL)
{
LsapFreeLsaHeap( TokenUserInformation );
}
if (!NT_SUCCESS(Status))
{
LsapAuditFailed( Status );
}
return Status;
}
VOID
LsapAdtPolicyChange(
IN USHORT EventCategory,
IN ULONG EventID,
IN USHORT EventType,
IN PSID ClientSid,
IN LUID CallerAuthenticationId,
IN PLSARM_POLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo
)
/*++
Routine Description:
Generates an audit for a policy change event.
The decision to generate this audit is made in LsapAdtGenerateLsaAuditEvent.
Arguments:
EventCategory - The category of this audit.
EventID - The event we are auditing.
EventType - Whether the audit is success or failure.
ClientSid - The SID of the user performing the policy change.
CallerAuthenticationId - The Authentication id of the user.
PolicyAuditEventsInfo - The information to audit.
Return Value:
None.
Note:
--*/
{
PPOLICY_AUDIT_EVENT_OPTIONS EventAuditingOptions;
SE_ADT_PARAMETER_ARRAY AuditParameters;
UNICODE_STRING Enabled;
UNICODE_STRING Disabled;
ULONG i;
RtlInitUnicodeString( &Enabled, L"+" );
RtlInitUnicodeString( &Disabled, L"-" );
EventAuditingOptions = PolicyAuditEventsInfo->EventAuditingOptions;
//
// Build an audit parameters structure.
//
RtlZeroMemory (
(PVOID) &AuditParameters,
sizeof( AuditParameters )
);
AuditParameters.CategoryId = EventCategory;
AuditParameters.AuditId = EventID;
AuditParameters.Type = EventType;
AuditParameters.ParameterCount = 0;
//
// User Sid
//
LsapSetParmTypeSid( AuditParameters, AuditParameters.ParameterCount, ClientSid );
AuditParameters.ParameterCount++;
//
// Subsystem name (if available)
//
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LsapSubsystemName );
AuditParameters.ParameterCount++;
//
// If auditing is disabled, mark all options as disabled. Otherwise
// mark them as the appropriate
//
for ( i=0; i<POLICY_AUDIT_EVENT_TYPE_COUNT; i++ ) {
LsapSetParmTypeString(
AuditParameters,
AuditParameters.ParameterCount,
(EventAuditingOptions[i] & POLICY_AUDIT_EVENT_SUCCESS ? &Enabled : &Disabled)
);
AuditParameters.ParameterCount++;
LsapSetParmTypeString(
AuditParameters,
AuditParameters.ParameterCount,
(EventAuditingOptions[i] & POLICY_AUDIT_EVENT_FAILURE ? &Enabled : &Disabled)
);
AuditParameters.ParameterCount++;
}
//
// Caller's Authentication information
//
LsapSetParmTypeLogonId( AuditParameters, AuditParameters.ParameterCount, CallerAuthenticationId );
AuditParameters.ParameterCount++;
( VOID ) LsapAdtWriteLog( &AuditParameters );
return;
}
NTSTATUS
LsapAdtGenerateDomainPolicyChangeAuditEvent(
IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass,
IN USHORT AuditEventType,
IN LSAP_DB_ATTRIBUTE* OldAttributes,
IN LSAP_DB_ATTRIBUTE* NewAttributes,
IN ULONG AttributeCount
)
/*++
Routine Description:
Generate an audit event when any of the following policies changes:
- PolicyDomainEfsInformation
- PolicyDomainKerberosTicketInformation
Arguments:
InformationClass - type of policy that changed
AuditEventType - The type of audit event to be generated.
EVENTLOG_AUDIT_SUCCESS or EVENTLOG_AUDIT_FAILURE
OldAttributes - pointer to array of old attributes
NewAttributes - pointer to array of new attributes
AttributeCount - number of attributes
Return Value:
NTSTATUS - Standard Nt Result Code
Notes:
--*/
{
NTSTATUS Status=STATUS_SUCCESS;
SE_ADT_PARAMETER_ARRAY AuditParameters;
ULONG AuditId;
LPWSTR AttributeChanges=NULL;
UNICODE_STRING ChangesToAttributes;
LUID ClientAuthenticationId;
PTOKEN_USER TokenUserInformation=NULL;
BOOLEAN bAudit;
Status = LsapQueryClientInfo(
&TokenUserInformation,
&ClientAuthenticationId
);
if ( !NT_SUCCESS( Status )) {
goto Cleanup;
}
Status = LsapAdtAuditingEnabledByLogonId(
AuditCategoryPolicyChange,
&ClientAuthenticationId,
AuditEventType,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit)
{
goto Cleanup;
}
switch (InformationClass) {
default:
ASSERT(FALSE);
goto Cleanup;
break;
case PolicyDomainEfsInformation:
AuditId = SE_AUDITID_EFS_POLICY_CHANGE;
break;
case PolicyDomainKerberosTicketInformation:
AuditId = SE_AUDITID_KERBEROS_POLICY_CHANGE;
break;
}
Status = LsapAdtGetDbAttributesChangeString( OldAttributes,
NewAttributes,
AttributeCount,
&AttributeChanges );
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
RtlInitUnicodeString(&ChangesToAttributes, AttributeChanges);
Status =
LsapAdtInitParametersArray(
&AuditParameters,
SE_CATEGID_POLICY_CHANGE,
AuditId,
AuditEventType,
4,
//
// User Sid
//
SeAdtParmTypeSid, TokenUserInformation->User.Sid,
//
// Subsystem name (if available)
//
SeAdtParmTypeString, &LsapSubsystemName,
//
// Caller's Authentication information
//
SeAdtParmTypeLogonId, ClientAuthenticationId,
//
// Changes to attributes
//
SeAdtParmTypeString, &ChangesToAttributes);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
( VOID ) LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (!NT_SUCCESS(Status))
{
LsapAuditFailed(Status);
}
if (TokenUserInformation != NULL)
{
LsapFreeLsaHeap( TokenUserInformation );
}
LsapFreeLsaHeap( AttributeChanges );
return Status;
}
VOID
LsapAdtGetAttributeValueString(
IN LSAP_DB_ATTRIBUTE* Attribute,
OUT LPWSTR ValueString OPTIONAL,
IN OUT PULONG RequiredLength
)
/*++
Routine Description:
Generate a string representation of the value of an attribute
Arguments:
Attribute - pointer to attribute
ValueString - receives a string representation of the value of Attribute
RequiredLength - pointer to length of ValueString
Return Value:
None
Notes:
--*/
{
WCHAR Buffer[32];
ULONG Length;
if (Attribute->AttributeValue) {
switch (Attribute->DbNameIndex) {
default:
lstrcpy(Buffer, L"unknown");
break;
// binary blob
case PolEfDat:
lstrcpy(Buffer, L"<binary data>");
break;
// ULONG
case KerOpts:
swprintf(Buffer, L"0x%x", *((ULONG*) Attribute->AttributeValue));
break;
// LARGE_INTEGER
case KerMinT:
case KerMaxT:
case KerMaxR:
case KerProxy:
case KerLogoff:
swprintf(Buffer, L"0x%I64x",
*((ULONGLONG*) Attribute->AttributeValue));
break;
}
} else {
lstrcpy(Buffer, L"none");
}
Length = lstrlen(Buffer);
if (ValueString && Length <= *RequiredLength)
{
CopyMemory(
ValueString,
Buffer,
Length * sizeof(WCHAR));
}
*RequiredLength = Length;
}
VOID
LsapAdtGetDbAttributeChangeString(
IN LSAP_DB_ATTRIBUTE* OldAttribute,
IN LSAP_DB_ATTRIBUTE* NewAttribute,
OUT LPWSTR AttributeChangeString, OPTIONAL
IN OUT PULONG RequiredLength
)
/*++
Routine Description:
Given an old attribute and a new attribute, return
a string representation of the difference between the two.
If there are no changes, RequiredLength is returned as 0
and AttributeChangeString is left unchanged;
otherwise if AttributeChangeString is non-NULL, the change is
written to it as:
<ParameterName>: <new value> (<old value>)
Arguments:
OldAttribute - pointer to old attribute
NewAttribute - pointer to new attribute
AttributeChangeString - if non-NULL, receives the string representation
of the difference between OldAttribute and NewAttribute
RequiredLength - pointer to length of AttributeChangeString
Return Value:
None
Notes:
--*/
{
PWSTR TmpString;
ULONG ChangeStringLength = 0;
ULONG ValueLength;
//
// do the processing only if there is a change in value
//
if ((OldAttribute->AttributeValue && NewAttribute->AttributeValue &&
(0 != memcmp(OldAttribute->AttributeValue,
NewAttribute->AttributeValue,
OldAttribute->AttributeValueLength))) ||
(OldAttribute->AttributeValue && !NewAttribute->AttributeValue) ||
(!OldAttribute->AttributeValue && NewAttribute->AttributeValue))
{
ChangeStringLength += OldAttribute->AttributeName->Length / sizeof(WCHAR);
ChangeStringLength += 2; // ": "
LsapAdtGetAttributeValueString(NewAttribute, 0, &ValueLength);
ChangeStringLength += ValueLength;
ChangeStringLength += 2; // " ("
LsapAdtGetAttributeValueString(OldAttribute, 0, &ValueLength);
ChangeStringLength += ValueLength;
ChangeStringLength += 4; // "); "
if (AttributeChangeString && ChangeStringLength <= *RequiredLength)
{
//
// Parameter Name
//
lstrcpy(AttributeChangeString, OldAttribute->AttributeName->Buffer);
ChangeStringLength = OldAttribute->AttributeName->Length / sizeof(WCHAR);
TmpString = AttributeChangeString + ChangeStringLength;
lstrcpy(TmpString, L": ");
ChangeStringLength += 2;
TmpString = AttributeChangeString + ChangeStringLength;
//
// Old value
//
ValueLength = *RequiredLength - ChangeStringLength;
LsapAdtGetAttributeValueString( NewAttribute, TmpString, &ValueLength );
ChangeStringLength += ValueLength;
TmpString = AttributeChangeString + ChangeStringLength;
//
// New value
//
lstrcpy(TmpString, L" (");
ChangeStringLength += 2;
TmpString = AttributeChangeString + ChangeStringLength;
ValueLength = *RequiredLength - ChangeStringLength;
LsapAdtGetAttributeValueString( OldAttribute, TmpString, &ValueLength );
ChangeStringLength += ValueLength;
TmpString = AttributeChangeString + ChangeStringLength;
//
// Don't copy the terminating '\0' in order to avoid a BO !
//
CopyMemory(TmpString, L"); ", 4 * sizeof(WCHAR));
ChangeStringLength += 4;
}
}
*RequiredLength = ChangeStringLength;
}
NTSTATUS
LsapAdtGetDbAttributesChangeString(
IN LSAP_DB_ATTRIBUTE* OldAttributes,
IN LSAP_DB_ATTRIBUTE* NewAttributes,
IN ULONG AttributeCount,
OUT LPWSTR* AttributeChangeString
)
/*++
Routine Description:
Given old attributes and new attributes, return a string representation
of the difference between old and new attributes.
If there are no changes, "--" is returned,
otherwise each change is written to the string as:
<ParameterName>: <new value> (<old value>)
This function is used for writing information about
changes to certain policies to the audit log.
Arguments:
OldAttributes - pointer to array of old attributes
NewAttributes - pointer to array of new attributes
AttributeCount - Number of attributes.
AttributeChangeString - pointer to string that receives the diff.
Return Value:
NTSTATUS - Standard Nt Result Code
Notes:
Memory allocated for AttributeChangeString must be freed by the
caller using LsapFreeLsaHeap.
--*/
{
NTSTATUS Status=STATUS_SUCCESS;
LSAP_DB_ATTRIBUTE* OldAttribute;
LSAP_DB_ATTRIBUTE* NewAttribute;
ULONG TmpStringLength;
ULONG TotalRequiredLength;
LPWSTR TmpString;
UINT AttributeNumber;
USHORT n=1;
OldAttribute = OldAttributes;
NewAttribute = NewAttributes;
TotalRequiredLength = 0;
//
// first find out the size of the buffer required
//
for (AttributeNumber = 0; AttributeNumber < AttributeCount; AttributeNumber++) {
LsapAdtGetDbAttributeChangeString( OldAttribute, NewAttribute,
NULL, &TmpStringLength );
OldAttribute++;
NewAttribute++;
TotalRequiredLength += TmpStringLength;
}
//
// reserve space for '--'
//
if (!TotalRequiredLength) {
n += 2;
}
*AttributeChangeString = TmpString =
LsapAllocateLsaHeap((TotalRequiredLength+n)*sizeof(WCHAR));
if ( TmpString ) {
if (TotalRequiredLength) {
//
// Now get the actual string
//
OldAttribute = OldAttributes;
NewAttribute = NewAttributes;
for (AttributeNumber = 0;
AttributeNumber < AttributeCount;
AttributeNumber++) {
TmpStringLength = TotalRequiredLength;
LsapAdtGetDbAttributeChangeString( OldAttribute, NewAttribute,
TmpString, &TmpStringLength );
TmpString += TmpStringLength;
OldAttribute++;
NewAttribute++;
}
*TmpString = L'\0';
} else {
lstrcpy(TmpString, L"--");
}
} else {
Status = STATUS_NO_MEMORY;
}
return Status;
}
PLUID LsaFilterPrivileges[] =
{
&ChangeNotifyPrivilege,
&AuditPrivilege,
&CreateTokenPrivilege,
&AssignPrimaryTokenPrivilege,
&BackupPrivilege,
&RestorePrivilege,
&DebugPrivilege,
NULL
};
VOID
LsapAdtAuditSpecialPrivileges(
PPRIVILEGE_SET Privileges,
LUID LogonId,
PSID UserSid
)
/*++
Routine Description:
Audits the assignment of special privileges at logon time.
Arguments:
Privileges - List of privileges being assigned.
Return Value:
None.
--*/
{
PPRIVILEGE_SET Buffer = NULL;
PLUID *FilterPrivilege = NULL;
ULONG i;
SE_ADT_PARAMETER_ARRAY AuditParameters;
BOOLEAN bAuditPrivUse = FALSE;
BOOLEAN bAuditLogon = FALSE;
NTSTATUS Status = STATUS_SUCCESS;
if ( (Privileges == NULL) || (Privileges->PrivilegeCount == 0) ) {
goto Cleanup;
}
//
// allow this audit to be generated when either the logon/logoff
// or the priv-use category is enabled
//
Status = LsapAdtAuditingEnabledByLogonId(
AuditCategoryPrivilegeUse,
&LogonId,
EVENTLOG_AUDIT_SUCCESS,
&bAuditPrivUse
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsapAdtAuditingEnabledByLogonId(
AuditCategoryLogon,
&LogonId,
EVENTLOG_AUDIT_SUCCESS,
&bAuditLogon
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// if neither category is set, return quickly
//
if ( !bAuditPrivUse && !bAuditLogon ) {
goto Cleanup;
}
DsysAssertMsg( IsValidPrivilegeCount(Privileges->PrivilegeCount),
"LsapAdtAuditSpecialPrivileges" );
//
// We can't need any more space than what's being passed in.
//
Buffer = (PPRIVILEGE_SET)LsapAllocateLsaHeap( LsapPrivilegeSetSize( Privileges ) );
if ( Buffer == NULL ) {
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
Buffer->PrivilegeCount = 0;
//
// For each privilege in the privilege set, see if it's in the filter
// list.
//
for ( i=0; i<Privileges->PrivilegeCount; i++) {
FilterPrivilege = LsaFilterPrivileges;
do {
if ( RtlEqualLuid( &Privileges->Privilege[i].Luid, *FilterPrivilege )) {
Buffer->Privilege[Buffer->PrivilegeCount].Luid = **FilterPrivilege;
Buffer->PrivilegeCount++;
}
} while ( *++FilterPrivilege != NULL );
}
if ( Buffer->PrivilegeCount == 0 ) {
goto Cleanup;
}
//
// We matched on at least one, generate an audit.
//
RtlZeroMemory ((PVOID) &AuditParameters, sizeof( AuditParameters ));
AuditParameters.CategoryId = SE_CATEGID_PRIVILEGE_USE;
AuditParameters.AuditId = SE_AUDITID_ASSIGN_SPECIAL_PRIV;
AuditParameters.Type = EVENTLOG_AUDIT_SUCCESS;
AuditParameters.ParameterCount = 0;
LsapSetParmTypeSid( AuditParameters, AuditParameters.ParameterCount, UserSid );
AuditParameters.ParameterCount++;
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LsapSubsystemName );
AuditParameters.ParameterCount++;
LsapSetParmTypeLogonId( AuditParameters, AuditParameters.ParameterCount, LogonId );
AuditParameters.ParameterCount++;
LsapSetParmTypePrivileges( AuditParameters, AuditParameters.ParameterCount, Buffer );
AuditParameters.ParameterCount++;
( VOID ) LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (!NT_SUCCESS(Status)) {
LsapAuditFailed(Status);
}
if (Buffer != NULL) {
LsapFreeLsaHeap( Buffer );
}
return;
}
VOID
LsapAdtAuditPackageLoad(
PUNICODE_STRING PackageFileName
)
/*++
Routine Description:
Audits the loading of an authentication package.
Arguments:
PackageFileName - The name of the package being loaded.
Return Value:
None.
--*/
{
SE_ADT_PARAMETER_ARRAY AuditParameters;
NTSTATUS Status;
BOOLEAN bAudit;
Status = LsapAdtAuditingEnabledBySid(
AuditCategorySystem,
LsapLocalSystemSid,
EVENTLOG_AUDIT_SUCCESS,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit) {
goto Cleanup;
}
RtlZeroMemory (
(PVOID) &AuditParameters,
sizeof( AuditParameters )
);
AuditParameters.CategoryId = SE_CATEGID_SYSTEM;
AuditParameters.AuditId = SE_AUDITID_AUTH_PACKAGE_LOAD;
AuditParameters.Type = EVENTLOG_AUDIT_SUCCESS;
AuditParameters.ParameterCount = 0;
LsapSetParmTypeSid( AuditParameters, AuditParameters.ParameterCount, LsapLocalSystemSid );
AuditParameters.ParameterCount++;
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LsapSubsystemName );
AuditParameters.ParameterCount++;
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, PackageFileName );
AuditParameters.ParameterCount++;
( VOID ) LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (!NT_SUCCESS(Status)) {
LsapAuditFailed(Status);
}
return;
}
VOID
LsapAdtAuditLogonProcessRegistration(
IN PLSAP_AU_REGISTER_CONNECT_INFO_EX ConnectInfo
)
/*++
Routine Description:
Audits the registration of a logon process
Arguments:
ConnectInfo - Supplies the connection information for the new
logon process.
Return Value:
None.
--*/
{
NTSTATUS Status;
ANSI_STRING AnsiString;
UNICODE_STRING Unicode = {0};
PSZ LogonProcessNameBuffer = NULL;
SE_ADT_PARAMETER_ARRAY AuditParameters;
BOOLEAN bAudit;
Status = LsapAdtAuditingEnabledBySid(
AuditCategorySystem,
LsapLocalSystemSid,
EVENTLOG_AUDIT_SUCCESS,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit) {
goto Cleanup;
}
//
// Turn the name text in the ConnectInfo structure into
// something we can work with.
//
LogonProcessNameBuffer = (PSZ)LsapAllocateLsaHeap( ConnectInfo->LogonProcessNameLength+1 );
if ( LogonProcessNameBuffer == NULL ) {
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
RtlCopyMemory(
LogonProcessNameBuffer,
ConnectInfo->LogonProcessName,
ConnectInfo->LogonProcessNameLength
);
LogonProcessNameBuffer[ConnectInfo->LogonProcessNameLength] = 0;
RtlInitAnsiString( &AnsiString, LogonProcessNameBuffer );
Status = RtlAnsiStringToUnicodeString( &Unicode, &AnsiString, TRUE );
if ( !NT_SUCCESS( Status )) {
goto Cleanup;
}
RtlZeroMemory (
(PVOID) &AuditParameters,
sizeof( AuditParameters )
);
AuditParameters.CategoryId = SE_CATEGID_SYSTEM;
AuditParameters.AuditId = SE_AUDITID_SYSTEM_LOGON_PROC_REGISTER;
AuditParameters.Type = EVENTLOG_AUDIT_SUCCESS;
AuditParameters.ParameterCount = 0;
LsapSetParmTypeSid( AuditParameters, AuditParameters.ParameterCount, LsapLocalSystemSid );
AuditParameters.ParameterCount++;
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LsapSubsystemName );
AuditParameters.ParameterCount++;
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &Unicode );
AuditParameters.ParameterCount++;
( VOID ) LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (!NT_SUCCESS(Status)) {
LsapAuditFailed(Status);
}
LsapFreeLsaHeap( LogonProcessNameBuffer );
RtlFreeUnicodeString( &Unicode );
return;
}
VOID
LsapAdtSystemRestart(
PLSARM_POLICY_AUDIT_EVENTS_INFO AuditEventsInfo
)
/*++
Routine Description:
This function is called during LSA initialization to generate
a system restart event.
Arguments:
AuditEventsInfo - Auditing data.
Return Value:
NTSTATUS - Standard Nt Result Code.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
SE_ADT_PARAMETER_ARRAY AuditParameters;
BOOLEAN bAudit;
Status = LsapAdtAuditingEnabledBySid(
AuditCategorySystem,
LsapLocalSystemSid,
EVENTLOG_AUDIT_SUCCESS,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit) {
goto Cleanup;
}
//
// Construct an audit parameters array
// for the restart event.
//
RtlZeroMemory (
(PVOID) &AuditParameters,
sizeof( AuditParameters )
);
AuditParameters.CategoryId = SE_CATEGID_SYSTEM;
AuditParameters.AuditId = SE_AUDITID_SYSTEM_RESTART;
AuditParameters.Type = EVENTLOG_AUDIT_SUCCESS;
AuditParameters.ParameterCount = 0;
//
// User Sid
//
LsapSetParmTypeSid( AuditParameters, AuditParameters.ParameterCount, LsapLocalSystemSid );
AuditParameters.ParameterCount++;
//
// Subsystem name
//
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LsapSubsystemName );
AuditParameters.ParameterCount++;
( VOID ) LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (!NT_SUCCESS(Status)) {
LsapAuditFailed(Status);
}
return;
}
VOID
LsapAdtAuditLogon(
IN USHORT EventCategory,
IN ULONG EventID,
IN USHORT EventType,
IN PUNICODE_STRING AccountName,
IN PUNICODE_STRING AuthenticatingAuthority,
IN PUNICODE_STRING Source,
IN PUNICODE_STRING PackageName,
IN SECURITY_LOGON_TYPE LogonType,
IN PSID UserSid,
IN LUID AuthenticationId,
IN PUNICODE_STRING WorkstationName,
IN NTSTATUS LogonStatus,
IN NTSTATUS SubStatus,
IN LPGUID LogonGuid, OPTIONAL
IN PLUID CallerLogonId, OPTIONAL
IN PHANDLE CallerProcessID, OPTIONAL
IN PLSA_ADT_STRING_LIST TransittedServices, OPTIONAL
IN SOCKADDR* pSockAddr OPTIONAL
)
/*++
Routine Description:
Generates an audit of a logon event as appropriate.
Arguments:
Return Value:
None.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING AuthenticationIdString = { 0 };
BOOLEAN FreeWhenDone = FALSE;
SE_ADT_PARAMETER_ARRAY AuditParameters;
BOOL AuditingSuccess;
BOOL AuditingFailure;
PSID pSid;
PLSAP_LOGON_SESSION pLogonSession = NULL;
BOOLEAN bAudit = FALSE;
UNICODE_STRING LocalAccountName;
UNICODE_STRING LocalAuthenticatingAuthority;
UNICODE_STRING LocalWorkstationName;
//
// Get the system Audit settings
//
AuditingFailure = (EventType == EVENTLOG_AUDIT_FAILURE) && LsapAdtAuditingEnabledByCategory(AuditCategoryLogon, EVENTLOG_AUDIT_FAILURE);
AuditingSuccess = (EventType == EVENTLOG_AUDIT_SUCCESS) && LsapAdtAuditingEnabledByCategory(AuditCategoryLogon, EVENTLOG_AUDIT_SUCCESS);
//
// If this is a success audit then we have a real user sid. Check if there
// exist per user audit settings for the user which may override system
// settings.
//
// In case of failed logons, the auth packages do not pass us the
// user SID therefore we cannot check pua policy here
//
if (AuditingSuccess)
{
Status = LsapAdtAuditingEnabledByLogonId(
AuditCategoryLogon,
&AuthenticationId,
EVENTLOG_AUDIT_SUCCESS,
&bAudit
);
if (!NT_SUCCESS(Status) || !bAudit)
{
goto Finish;
}
}
//
// return quickly if auditing is not enabled
//
if ( !(AuditingFailure || AuditingSuccess || bAudit) )
{
return;
}
//
// Build an audit parameters structure.
//
RtlZeroMemory ( (PVOID) &AuditParameters, sizeof( AuditParameters ) );
AuditParameters.CategoryId = EventCategory;
AuditParameters.AuditId = EventID;
AuditParameters.Type = EventType;
AuditParameters.ParameterCount = 0;
//
// If this is a successful logon audit event and the caller did not
// supply a logon GUID, extract it from the logon session.
//
if ( AuditingSuccess && !LogonGuid &&
( EventType == EVENTLOG_AUDIT_SUCCESS ) )
{
pLogonSession = LsapLocateLogonSession( &AuthenticationId );
ASSERT( pLogonSession && L"LsapAdtAuditLogon: logon session not found" );
if ( pLogonSession )
{
LogonGuid = &pLogonSession->LogonGuid;
}
}
#if DBG
if ( AuditingSuccess )
{
DsysAssert( EventID != SE_AUDITID_DOMAIN_TRUST_INCONSISTENT );
}
#endif
//
// User Sid
//
pSid = AuditingSuccess ? UserSid : LsapLocalSystemSid;
LsapSetParmTypeSid( AuditParameters, AuditParameters.ParameterCount, pSid );
AuditParameters.ParameterCount++;
//
// Subsystem name
//
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LsapSubsystemName );
AuditParameters.ParameterCount++;
//
// Account name
//
if ( ARGUMENT_PRESENT( AccountName ) ) {
LocalAccountName = *AccountName;
if ( EventID == SE_AUDITID_UNKNOWN_USER_OR_PWD ) {
//
// For failed logons of type SE_AUDITID_UNKNOWN_USER_OR_PWD
// the user name can be invalid (for example,
// with embedded NULLs). This causes the
// eventlog to reject the string and we drop the audit.
//
// To avoid this, adjust the length parameter if necessary.
//
LocalAccountName.Length =
(USHORT) LsapSafeWcslen( LocalAccountName.Buffer,
LocalAccountName.MaximumLength );
}
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LocalAccountName );
}
AuditParameters.ParameterCount++;
//
// Authenticating Authority (domain name)
//
if ( ARGUMENT_PRESENT( AuthenticatingAuthority ) ) {
LocalAuthenticatingAuthority = *AuthenticatingAuthority;
//
// The domain name is used by NTLM as unauthenticated hint
// thus it can be invalid (for example,
// with embedded NULLs). This causes the
// eventlog to reject the string and we drop the audit.
//
// To avoid this, adjust the length parameter if necessary.
//
LocalAuthenticatingAuthority.Length =
(USHORT) LsapSafeWcslen( LocalAuthenticatingAuthority.Buffer,
LocalAuthenticatingAuthority.MaximumLength );
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LocalAuthenticatingAuthority );
}
AuditParameters.ParameterCount++;
if ( AuditingSuccess ) {
//
// Logon Id (as a string)
//
Status = LsapAdtBuildLuidString(
&AuthenticationId,
&AuthenticationIdString,
&FreeWhenDone
);
if ( NT_SUCCESS( Status )) {
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &AuthenticationIdString );
} else {
goto Finish;
}
AuditParameters.ParameterCount++;
}
//
// Logon Type
//
LsapSetParmTypeUlong( AuditParameters, AuditParameters.ParameterCount, LogonType );
AuditParameters.ParameterCount++;
//
// Source
//
if ( ARGUMENT_PRESENT( Source )) {
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, Source );
} else {
//
// No need to do anything here, since an empty entry will turn
// into a '-' in the output
//
}
AuditParameters.ParameterCount++;
//
// Authentication Package
//
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, PackageName );
AuditParameters.ParameterCount++;
//
// Workstation Name
//
if ( ARGUMENT_PRESENT( WorkstationName )) {
LocalWorkstationName = *WorkstationName;
//
// NTLM accepts wks name from clients. A client can supply
// invalid name (for example, with embedded NULLs). This causes
// eventlog to reject the string and we drop the audit.
//
// To avoid this, adjust the length parameter if necessary.
//
LocalWorkstationName.Length =
(USHORT) LsapSafeWcslen( LocalWorkstationName.Buffer,
LocalWorkstationName.MaximumLength );
LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LocalWorkstationName );
}
AuditParameters.ParameterCount++;
if ( EventID == SE_AUDITID_UNSUCCESSFUL_LOGON ) {
//
// we need to supply the logon status for this event,
// so that some information can be gleened from the log.
//
LsapSetParmTypeHexUlong( AuditParameters, AuditParameters.ParameterCount, LogonStatus );
AuditParameters.ParameterCount++;
LsapSetParmTypeHexUlong( AuditParameters, AuditParameters.ParameterCount, SubStatus );
AuditParameters.ParameterCount++;
}
//
// Logon GUID
//
if ( ARGUMENT_PRESENT( LogonGuid )) {
LsapSetParmTypeGuid( AuditParameters, AuditParameters.ParameterCount, LogonGuid );
AuditParameters.ParameterCount++;
}
//
// Caller Logon-ID
//
if ( ARGUMENT_PRESENT( CallerLogonId )) {
LsapSetParmTypeLogonId( AuditParameters, AuditParameters.ParameterCount, *CallerLogonId );
} else {
LsapSetParmTypeNoLogon( AuditParameters, AuditParameters.ParameterCount );
}
AuditParameters.ParameterCount++;
//
// Caller Process-ID
//
if ( ARGUMENT_PRESENT( CallerProcessID )) {
LsapSetParmTypePtr( AuditParameters, AuditParameters.ParameterCount, *CallerProcessID );
}
AuditParameters.ParameterCount++;
//
// Transitted Services (Kerberos only)
//
if ( ARGUMENT_PRESENT( TransittedServices )) {
LsapSetParmTypeStringList( AuditParameters, AuditParameters.ParameterCount, TransittedServices );
}
AuditParameters.ParameterCount++;
//
// IP address/port of caller
//
if ( ARGUMENT_PRESENT( pSockAddr )) {
LsapSetParmTypeSockAddr( AuditParameters, AuditParameters.ParameterCount, pSockAddr );
}
AuditParameters.ParameterCount++;
( VOID ) LsapAdtWriteLog( &AuditParameters );
Finish:
if (!NT_SUCCESS(Status))
{
LsapAuditFailed( Status );
}
if ( FreeWhenDone ) {
LsapFreeLsaHeap( AuthenticationIdString.Buffer );
}
if ( pLogonSession != NULL )
{
LsapReleaseLogonSession( pLogonSession );
}
}
VOID
LsapAuditLogon(
IN NTSTATUS LogonStatus,
IN NTSTATUS LogonSubStatus,
IN PUNICODE_STRING AccountName,
IN PUNICODE_STRING AuthenticatingAuthority,
IN PUNICODE_STRING WorkstationName,
IN PSID UserSid, OPTIONAL
IN SECURITY_LOGON_TYPE LogonType,
IN PTOKEN_SOURCE TokenSource,
IN PLUID LogonId
)
/*++
Routine Description/Arguments/Return value
See header comment for LsapAuditLogonHelper
--*/
{
LsapAuditLogonHelper(
LogonStatus,
LogonSubStatus,
AccountName,
AuthenticatingAuthority,
WorkstationName,
UserSid,
LogonType,
TokenSource,
LogonId,
NULL, // no logon guid
NULL, // caller logon-id
NULL, // caller process-id
NULL // no transitted services
);
}
VOID
LsapAuditLogonHelper(
IN NTSTATUS LogonStatus,
IN NTSTATUS LogonSubStatus,
IN PUNICODE_STRING AccountName,
IN PUNICODE_STRING AuthenticatingAuthority,
IN PUNICODE_STRING WorkstationName,
IN PSID UserSid, OPTIONAL
IN SECURITY_LOGON_TYPE LogonType,
IN PTOKEN_SOURCE TokenSource,
IN PLUID LogonId,
IN LPGUID LogonGuid, OPTIONAL
IN PLUID CallerLogonId, OPTIONAL
IN PHANDLE CallerProcessID, OPTIONAL
IN PLSA_ADT_STRING_LIST TransittedServices OPTIONAL
)
/*++
Routine Description:
Helper routine for security packages to generate a logon audit
Arguments:
LogonStatus - Status code for the logon.
LogonSubStatus - more detailed Status code for the logon.
AccountName - Name of principal attempting logon.
AuthenticatingAuthority - Authority validating the logon.
Workstation - Machine from which the logon was attempted.
For a network logon, this is the client machine.
UserSid - Sid for the logged on account.
LogonType - Type of logon, such as Network, Interactive, etc.
TokenSource - Source for the token.
LogonId - If the logon was successful,
the logon ID for the logon session.
LogonGuid - globally unique ID for a logon.
This is supported only by the kerberos package.
CallerLogonId - Logon-ID of the caller.
For example, if foo calls LsaLogonUser to create
a logon session for bar. This will be the logon-ID
of foo.
CallerProcessID - Process ID of the calling process.
Return Value:
None.
--*/
{
ANSI_STRING AnsiSourceContext;
CHAR AnsiBuffer[TOKEN_SOURCE_LENGTH + 2];
UNICODE_STRING UnicodeSourceContext;
WCHAR UnicodeBuffer[TOKEN_SOURCE_LENGTH + 2];
NTSTATUS Status;
USHORT EventType;
USHORT EventCategory;
ULONG EventID;
PLSAP_SECURITY_PACKAGE SecurityPackage;
ULONG_PTR PackageId;
PLSA_CALL_INFO pCallInfo;
SOCKADDR* pSockAddr = NULL;
SOCKADDR EmptySockAddr = {0};
//
// get the IP address/port of the caller
//
pCallInfo = LsapGetCurrentCall();
if ( pCallInfo == NULL ) {
//
// If we cannot get the call info then use the 0.0.0.0:0 address.
//
pSockAddr = &EmptySockAddr;
pSockAddr->sa_family = AF_INET;
} else {
pSockAddr = (SOCKADDR*) pCallInfo->IpAddress;
}
PackageId = GetCurrentPackageId();
DsysAssertMsg( PackageId != SPMGR_ID, "LsapAuditLogon" );
SecurityPackage = SpmpLocatePackage( PackageId );
DsysAssertMsg( SecurityPackage != NULL, "LsapAuditLogon" );
//
// Audit the logon attempt. The event type and logged information
// will depend to some extent on the whether we failed and why.
//
//
// Turn the SourceContext into something we can
// work with.
//
AnsiSourceContext.Buffer = AnsiBuffer;
AnsiSourceContext.Length = TOKEN_SOURCE_LENGTH * sizeof( CHAR );
AnsiSourceContext.MaximumLength = (TOKEN_SOURCE_LENGTH + 2) * sizeof( CHAR );
UnicodeSourceContext.Buffer = UnicodeBuffer;
UnicodeSourceContext.MaximumLength = (TOKEN_SOURCE_LENGTH + 2) * sizeof( WCHAR );
RtlCopyMemory(
AnsiBuffer,
TokenSource->SourceName,
TOKEN_SOURCE_LENGTH * sizeof( CHAR )
);
Status = RtlAnsiStringToUnicodeString(
&UnicodeSourceContext,
&AnsiSourceContext,
FALSE
);
if ( NT_SUCCESS( Status )) {
UnicodeSourceContext.Length =
(USHORT) LsapSafeWcslen( UnicodeSourceContext.Buffer,
UnicodeSourceContext.MaximumLength );
} else {
UnicodeSourceContext.Buffer = NULL;
//
// we cannot fail the audit because of this but catch the
// internal clients who supply bad source contexts
//
DsysAssertMsg( FALSE, "LsapAuditLogon: could not convert AnsiSourceContext to unicode" );
}
//
// Assume the logon failed, reset if necessary.
//
EventCategory = SE_CATEGID_LOGON;
EventType = EVENTLOG_AUDIT_FAILURE;
switch ( LogonStatus )
{
case STATUS_SUCCESS:
{
//
// Use a separate event for network logons
//
if (( LogonType == Network ) ||
( LogonType == NetworkCleartext ))
{
EventID = SE_AUDITID_NETWORK_LOGON;
}
else
{
EventID = SE_AUDITID_SUCCESSFUL_LOGON;
}
EventType = EVENTLOG_AUDIT_SUCCESS;
break;
}
case STATUS_BAD_VALIDATION_CLASS:
EventID = SE_AUDITID_UNSUCCESSFUL_LOGON;
break;
case STATUS_ACCOUNT_EXPIRED:
EventID = SE_AUDITID_ACCOUNT_EXPIRED;
break;
case STATUS_NETLOGON_NOT_STARTED:
EventID = SE_AUDITID_NETLOGON_NOT_STARTED;
break;
case STATUS_ACCOUNT_LOCKED_OUT:
EventID = SE_AUDITID_ACCOUNT_LOCKED;
break;
case STATUS_LOGON_TYPE_NOT_GRANTED:
EventID = SE_AUDITID_LOGON_TYPE_RESTR;
break;
case STATUS_PASSWORD_MUST_CHANGE:
EventID = SE_AUDITID_PASSWORD_EXPIRED;
break;
case STATUS_ACCOUNT_RESTRICTION:
{
switch ( LogonSubStatus )
{
case STATUS_PASSWORD_EXPIRED:
EventID = SE_AUDITID_PASSWORD_EXPIRED;
break;
case STATUS_ACCOUNT_DISABLED:
EventID = SE_AUDITID_ACCOUNT_DISABLED;
break;
case STATUS_INVALID_LOGON_HOURS:
EventID = SE_AUDITID_ACCOUNT_TIME_RESTR;
break;
case STATUS_INVALID_WORKSTATION:
EventID = SE_AUDITID_WORKSTATION_RESTR;
break;
default:
EventID = SE_AUDITID_UNKNOWN_USER_OR_PWD;
break;
}
break;
}
case STATUS_LOGON_FAILURE:
{
if ( ( LogonSubStatus == STATUS_WRONG_PASSWORD ) ||
( LogonSubStatus == STATUS_NO_SUCH_USER ) )
{
EventID = SE_AUDITID_UNKNOWN_USER_OR_PWD;
}
else if ( LogonSubStatus == STATUS_DOMAIN_TRUST_INCONSISTENT )
{
EventID = SE_AUDITID_DOMAIN_TRUST_INCONSISTENT;
}
else
{
EventID = SE_AUDITID_UNSUCCESSFUL_LOGON;
}
break;
}
default:
EventID = SE_AUDITID_UNSUCCESSFUL_LOGON;
break;
}
LsapAdtAuditLogon( EventCategory,
EventID,
EventType,
AccountName,
AuthenticatingAuthority,
&UnicodeSourceContext,
&SecurityPackage->Name,
LogonType,
UserSid,
*LogonId,
WorkstationName,
LogonStatus,
LogonSubStatus,
LogonGuid,
CallerLogonId,
CallerProcessID,
TransittedServices,
pSockAddr
);
}
VOID
LsapAdtAuditLogoff(
PLSAP_LOGON_SESSION Session
)
/*++
Routine Description:
Generates a logoff audit. The caller is responsible for determining
if logoff auditing is enabled.
Arguments:
Session - Points to the logon session being removed.
Return Value:
None.
--*/
{
SE_ADT_PARAMETER_ARRAY AuditParameters;
NTSTATUS Status;
UNICODE_STRING usLogonId;
BOOLEAN fFreeLogonId=FALSE;
RtlZeroMemory ( &usLogonId, sizeof(UNICODE_STRING) );
//
// normally we would simply store the logon-id to be audited
// as SeAdtParmTypeLogonId. But in this case, the logon session
// will have gone away by the time we try to convert it
// to a string representation in LsapAdtDemarshallAuditInfo.
// using LsapGetLogonSessionAccountInfo.
//
// To avoid this, we pre-convert the logon-id here
//
Status = LsapAdtBuildLuidString( &Session->LogonId,
&usLogonId, &fFreeLogonId );
if ( !NT_SUCCESS(Status) )
{
goto Cleanup;
}
Status =
LsapAdtInitParametersArray(
&AuditParameters,
SE_CATEGID_LOGON,
SE_AUDITID_LOGOFF,
EVENTLOG_AUDIT_SUCCESS,
6, // there are 6 params to init
//
// User Sid
//
SeAdtParmTypeSid, Session->UserSid,
//
// Subsystem name (if available)
//
SeAdtParmTypeString, &LsapSubsystemName,
//
// User
//
SeAdtParmTypeString, &Session->AccountName,
//
// Domain
//
SeAdtParmTypeString, &Session->AuthorityName,
//
// LogonId
//
SeAdtParmTypeString, &usLogonId,
//
// Logon Type
//
SeAdtParmTypeUlong, Session->LogonType
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
( VOID ) LsapAdtWriteLog( &AuditParameters );
Cleanup:
if (fFreeLogonId)
{
LsapFreeLsaHeap(usLogonId.Buffer);
}
}
VOID
LsapAdtAuditPerUserTableCreation(
BOOLEAN bSuccess
)
/*++
Routine Description:
Generates an audit to report that the per user table was regenerated. The
table should be locked for read access during this call.
This routine will generate a single audit to indicate that the table
has been created. It will then generate individual audits for each
user that has an element in the per user audit table.
Arguments:
None.
Return Value:
None.
--*/
{
SE_ADT_PARAMETER_ARRAY AuditParameters;
NTSTATUS Status;
BOOLEAN bAudit;
ULONG i;
ULONG j;
PPER_USER_AUDITING_ELEMENT pElement = NULL;
LUID TableId;
ULONG AuditSettings[POLICY_AUDIT_EVENT_TYPE_COUNT];
if (!AllocateLocallyUniqueId(&TableId))
{
Status = LsapWinerrorToNtStatus(GetLastError());
goto Cleanup;
}
//
// First log an audit to indicate that the table is being
// created.
//
Status = LsapAdtAuditingEnabledBySid(
AuditCategoryPolicyChange,
LsapLocalSystemSid,
EVENTLOG_AUDIT_SUCCESS,
&bAudit
);
if (!NT_SUCCESS( Status ))
{
goto Cleanup;
}
if (bAudit)
{
Status =
LsapAdtInitParametersArray(
&AuditParameters,
SE_CATEGID_POLICY_CHANGE,
SE_AUDITID_PER_USER_AUDIT_TABLE_CREATION,
bSuccess ? EVENTLOG_AUDIT_SUCCESS : EVENTLOG_AUDIT_FAILURE,
4,
//
// User Sid
//
SeAdtParmTypeSid, LsapLocalSystemSid,
//
// Subsystem name (if available)
//
SeAdtParmTypeString, &LsapSubsystemName,
//
// Number of users in the per user table
//
SeAdtParmTypeUlong, bSuccess ? LsapAdtPerUserAuditUserCount : 0,
//
// Table ID
//
SeAdtParmTypeLuid, TableId
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
(VOID)LsapAdtWriteLog(&AuditParameters);
//
// If this is a failure audit, then exit now.
//
if (!bSuccess)
{
return;
}
}
//
// Now log audits for the individual records in the table.
//
for (i = 0; i < PER_USER_AUDITING_POLICY_TABLE_SIZE; i++)
{
pElement = LsapAdtPerUserAuditingTable[i];
while (pElement)
{
RtlZeroMemory(
AuditSettings,
sizeof(AuditSettings)
);
for (j = 0; j < pElement->TokenAuditPolicy.PolicyCount; j++)
{
AuditSettings[pElement->TokenAuditPolicy.Policy[j].Category] = pElement->TokenAuditPolicy.Policy[j].PolicyMask;
}
Status =
LsapAdtInitParametersArray(
&AuditParameters,
SE_CATEGID_POLICY_CHANGE,
SE_AUDITID_PER_USER_AUDIT_TABLE_ELEMENT_CREATION,
EVENTLOG_AUDIT_SUCCESS,
13,
//
// User Sid
//
SeAdtParmTypeSid, LsapLocalSystemSid,
//
// Subsystem name (if available)
//
SeAdtParmTypeString, &LsapSubsystemName,
//
// User Sid
//
SeAdtParmTypeSid, pElement->pSid,
//
// Table Id
//
SeAdtParmTypeLuid, TableId,
//
// System
//
SeAdtParmTypeHexUlong, AuditSettings[AuditCategorySystem],
//
// Logon
//
SeAdtParmTypeHexUlong, AuditSettings[AuditCategoryLogon],
//
// Object Access
//
SeAdtParmTypeHexUlong, AuditSettings[AuditCategoryObjectAccess],
//
// Privilege Use
//
SeAdtParmTypeHexUlong, AuditSettings[AuditCategoryPrivilegeUse],
//
// Detailed Tracking
//
SeAdtParmTypeHexUlong, AuditSettings[AuditCategoryDetailedTracking],
//
// Policy Change
//
SeAdtParmTypeHexUlong, AuditSettings[AuditCategoryPolicyChange],
//
// Account Management
//
SeAdtParmTypeHexUlong, AuditSettings[AuditCategoryAccountManagement],
//
// DS Access
//
SeAdtParmTypeHexUlong, AuditSettings[AuditCategoryDirectoryServiceAccess],
//
// Account Logon
//
SeAdtParmTypeHexUlong, AuditSettings[AuditCategoryAccountLogon]
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
(VOID)LsapAdtWriteLog(&AuditParameters);
pElement = pElement->Next;
}
}
Cleanup:
if (!NT_SUCCESS( Status ))
{
LsapAuditFailed( Status );
}
}
VOID
LsapAdtLogAuditFailureEvent(
NTSTATUS AuditStatus
)
/*++
Routine Description:
Generates SE_AUDITID_UNABLE_TO_LOG_EVENTS event
Arguments:
AuditStatus : failure code
Return Value:
None.
--*/
{
SE_ADT_PARAMETER_ARRAY AuditParameters;
NTSTATUS Status = STATUS_SUCCESS;
ULONG CrashOnAuditFailState;
//
// determine the CrashOnAuditFailState value
//
if ( LsapCrashOnAuditFail )
{
CrashOnAuditFailState = 1;
}
else if ( LsapAllowAdminLogonsOnly )
{
CrashOnAuditFailState = 2;
}
else
{
CrashOnAuditFailState = 0;
}
Status =
LsapAdtInitParametersArray(
&AuditParameters,
SE_CATEGID_SYSTEM,
SE_AUDITID_UNABLE_TO_LOG_EVENTS,
EVENTLOG_AUDIT_SUCCESS,
4, // there are 4 params to init
//
// User Sid
//
SeAdtParmTypeSid, LsapLocalSystemSid,
//
// Subsystem name (if available)
//
SeAdtParmTypeString, &LsapSubsystemName,
//
// Audit failure code
//
SeAdtParmTypeHexUlong, AuditStatus,
//
// value of CrashOnAuditFail
//
SeAdtParmTypeUlong, CrashOnAuditFailState
);
AdtAssert(NT_SUCCESS(Status), ("LsapAdtLogAuditFailureEvent: LsapAdtInitParametersArray failed: %x", Status));
//
// note: we do not call LsapAuditFailed here because this function
// itself gets called by LsapAuditFailed. We just hope
// for the best.
//
//
// call LsapAdtDemarshallAuditInfo directly so that the audit event
// will bypass the queue and go directly to the eventlog.
//
Status = LsapAdtDemarshallAuditInfo( &AuditParameters );
AdtAssert(NT_SUCCESS(Status), ("LsapAdtLogAuditFailureEvent: LsapAdtDemarshallAuditInfo failed: %x", Status));
//
// now flush the eventlog
//
Status = LsapFlushSecurityLog();
AdtAssert(NT_SUCCESS(Status), ("LsapAdtLogAuditFailureEvent: ElfFlushEventLog failed: %x", Status));
}