|
|
/*++
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)); }
|