/*++ 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 #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; iUser.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""); 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: : () 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: : () 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; iPrivilegeCount; 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)); }