/*++ 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" // ---------------------------------------------------------------------- // // Lsa Global flags to indicate if we are auditing logon events. // BOOLEAN LsapAuditSuccessfulLogons = FALSE; BOOLEAN LsapAuditFailedLogons = FALSE; // // 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 succeds/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; static LPCWSTR ObjectOperationNames[ObjectOperationDummyLast] = { L"None", L"Query" }; LsapEnterFunc("LsapAdtGenerateObjectAcessAuditEvent"); if (!LsapAdtIsAuditingEnabledForCategory( AuditCategoryObjectAccess, AuditEventType)) { goto FunctionReturn; } 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; } // // 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] ); LsapAdtInitParametersArray( &AuditParameters, SE_CATEGID_OBJECT_ACCESS, SE_AUDITID_OBJECT_OPERATION, AuditEventType, 11, // there are 11 params to init // // User Sid // SeAdtParmTypeSid, TokenUserInformation->User.Sid, // // Subsystem name (if available) // SeAdtParmTypeString, &LsapSubsystemName, // // Operation Type // SeAdtParmTypeString, &OperationTypeName, // // Object Type : index of this is 3, 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 : 3 is the index of ObjectType parameter // SeAdtParmTypeAccessMask, InternalHandle->RequestedAccess, 3, // // there are no object properties (object-type list) // SeAdtParmTypeNone, // // no additional information // SeAdtParmTypeNone ); ( VOID ) LsapAdtWriteLog( &AuditParameters, 0 ); Cleanup: if (TokenUserInformation != NULL) { LsapFreeLsaHeap( TokenUserInformation ); } if (!NT_SUCCESS(Status)) { LsapAuditFailed( Status ); } FunctionReturn: 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. LuidCount - Count of Locally Unique Ids being passed via the Luids parameter. If no Locally Unique Ids are passed, this parameter must be set to 0. Luids - Pointer to array of LuidCount Locally Unique Ids and their attributes. The attributes are ignored. If 0 is passed for the LuidCount parameter, this parameter is ignored and NULL may be specified. 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; UNREFERENCED_PARAMETER( ObjectHandle ); Status = LsapQueryClientInfo( &TokenUserInformation, &ClientAuthenticationId ); if ( !NT_SUCCESS( Status )) { goto Cleanup; } ClientSid = TokenUserInformation->User.Sid; 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. 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. LuidCount - Count of Locally Unique Ids being passed via the Luids parameter. If no Locally Unique Ids are passed, this parameter must be set to 0. Luids - Pointer to array of LuidCount Locally Unique Ids and their attributes. The attributes are ignored. If 0 is passed for the LuidCount parameter, this parameter is ignored and NULL may be specified. 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. Arguments: Return Value: None. --*/ { SE_ADT_PARAMETER_ARRAY AuditParameters; // // 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, 0 ); 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. 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. --*/ { SE_ADT_PARAMETER_ARRAY AuditParameters; UNICODE_STRING SystemAccessString; // // Build an audit parameters structure. // RtlZeroMemory ( (PVOID) &AuditParameters, sizeof( AuditParameters ) ); RtlInitUnicodeString( &SystemAccessString, szSystemAccess ); LsapAdtInitParametersArray( &AuditParameters, EventCategory, EventID, EventType, 5, SeAdtParmTypeSid, ClientSid, SeAdtParmTypeString, &LsapSubsystemName, SeAdtParmTypeLogonId, CallerAuthenticationId, SeAdtParmTypeString, &SystemAccessString, SeAdtParmTypeSid, TargetSid ); (VOID) LsapAdtWriteLog( &AuditParameters, 0 ); return; } 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 }; // // if auditing is not enabled, return asap // if ( !LsapAdtIsAuditingEnabledForCategory( AuditCategoryPolicyChange, EventType ) ) { goto Cleanup; } Status = LsapQueryClientInfo( &TokenUserInformation, &ClientAuthenticationId ); if ( !NT_SUCCESS( Status )) { goto Cleanup; } // // Build an audit parameters structure. // LsapAdtInitParametersArray( &AuditParameters, SE_CATEGID_POLICY_CHANGE, SE_AUDITID_TRUSTED_DOMAIN_ADD, EventType, 8, // there are 8 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 ); Status = LsapAdtWriteLog( &AuditParameters, 0 ); 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 }; // // if auditing is not enabled, return asap // if ( !LsapAdtIsAuditingEnabledForCategory( AuditCategoryPolicyChange, EventType ) ) { goto Cleanup; } 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 // // Build an audit parameters structure. // 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 ); Status = LsapAdtWriteLog( &AuditParameters, 0 ); 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 }; UNICODE_STRING TempName; // // if auditing is not enabled, return asap // if ( !LsapAdtIsAuditingEnabledForCategory( AuditCategoryPolicyChange, EventType ) ) { goto Cleanup; } Status = LsapQueryClientInfo( &TokenUserInformation, &ClientAuthenticationId ); if ( !NT_SUCCESS( Status )) { goto Cleanup; } AuditParameters.CategoryId = SE_CATEGID_POLICY_CHANGE; AuditParameters.AuditId = SE_AUDITID_TRUSTED_DOMAIN_MOD; AuditParameters.Type = EventType; AuditParameters.ParameterCount = 8; // // 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 ); } Status = LsapAdtWriteLog( &AuditParameters, 0 ); 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 is 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: --*/ { NTSTATUS Status = STATUS_SUCCESS; SE_ADT_PARAMETER_ARRAY AuditParameters = { 0 }; #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 // if ( !LsapAdtIsAuditingEnabledForCategory( AuditCategoryPolicyChange, EVENTLOG_AUDIT_SUCCESS ) ) { 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. // 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 ); Status = LsapAdtWriteLog( &AuditParameters, 0 ); 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 }; // // if auditing is not enabled, return asap // if ( !LsapAdtIsAuditingEnabledForCategory( AuditCategoryPolicyChange, EventType ) ) { goto Cleanup; } Status = LsapQueryClientInfo( &TokenUserInformation, &ClientAuthenticationId ); if ( !NT_SUCCESS( Status )) { goto Cleanup; } // // Build an audit parameters structure. // 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 ); Status = LsapAdtWriteLog( &AuditParameters, 0 ); 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 }; // // if auditing is not enabled, return asap // if ( !LsapAdtIsAuditingEnabledForCategory( AuditCategoryPolicyChange, EVENTLOG_AUDIT_SUCCESS ) ) { goto Cleanup; } Status = LsapQueryClientInfo( &TokenUserInformation, &ClientAuthenticationId ); if ( !NT_SUCCESS( Status )) { 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, 0 ); 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. 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 // if (PolicyAuditEventsInfo->AuditingMode) { for ( i=0; iUser.Sid, // // Subsystem name (if available) // SeAdtParmTypeString, &LsapSubsystemName, // // Caller's Authentication information // SeAdtParmTypeLogonId, ClientAuthenticationId, // // Changes to attributes // SeAdtParmTypeString, &ChangesToAttributes); ( VOID ) LsapAdtWriteLog( &AuditParameters, 0 ); Cleanup: if (TokenUserInformation != NULL) { LsapFreeLsaHeap( TokenUserInformation ); } LsapFreeLsaHeap( AttributeChanges ); return Status; } void LsapAdtGetAttributeValueString( IN LSAP_DB_ATTRIBUTE* Attribute, OUT LPWSTR ValueString) /*++ 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 Return Value: None Notes: --*/ { if (Attribute->AttributeValue) { switch (Attribute->DbNameIndex) { default: lstrcpy(ValueString, L"unknown"); break; // binary blob case PolEfDat: lstrcpy(ValueString, L""); break; // ULONG case KerOpts: swprintf(ValueString, L"0x%x", *((ULONG*) Attribute->AttributeValue)); break; // LARGE_INTEGER case KerMinT: case KerMaxT: case KerMaxR: case KerProxy: case KerLogoff: swprintf(ValueString, L"0x%I64x", *((ULONGLONG*) Attribute->AttributeValue)); break; } } else { lstrcpy(ValueString, L"none"); } } 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: --*/ { WCHAR ChangeString[256]; LPWSTR TmpString; ULONG ChangeStringLength=0; // // 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)) { // // Parameter Name // lstrcpy(ChangeString, OldAttribute->AttributeName->Buffer); ChangeStringLength = OldAttribute->AttributeName->Length/sizeof(WCHAR); TmpString = ChangeString + ChangeStringLength; lstrcpy(TmpString, L": "); ChangeStringLength += 2; TmpString = ChangeString + ChangeStringLength; // // Old value // LsapAdtGetAttributeValueString( NewAttribute, TmpString ); ChangeStringLength += lstrlen(TmpString); TmpString = ChangeString + ChangeStringLength; // // New value // lstrcpy(TmpString, L" ("); ChangeStringLength += 2; TmpString = ChangeString + ChangeStringLength; LsapAdtGetAttributeValueString( OldAttribute, TmpString ); ChangeStringLength += lstrlen(TmpString); TmpString = ChangeString + ChangeStringLength; lstrcpy(TmpString, L"); "); ChangeStringLength += 4; if (AttributeChangeString && (ChangeStringLength <= *RequiredLength)) { lstrcpy(AttributeChangeString, ChangeString); } } *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; } 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++; } } else { lstrcpy(TmpString, L"--"); } } else { Status = STATUS_NO_MEMORY; } return Status; } VOID LsapAdtAuditDiscardedAudits( ULONG NumberOfEventsDiscarded ) /*++ Routine Description: Audits the fact that we discarded some audits. Arguments: NumberOfEventsDiscarded - The number of events discarded. Return Value: None. --*/ { SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; NTSTATUS Status; SE_ADT_PARAMETER_ARRAY AuditParameters; if ( !LsapAdtEventsInformation.AuditingMode ) { return; } if (!(LsapAdtEventsInformation.EventAuditingOptions[AuditCategorySystem] & POLICY_AUDIT_EVENT_SUCCESS)) { return; } RtlZeroMemory ((PVOID) &AuditParameters, sizeof( AuditParameters )); AuditParameters.CategoryId = SE_CATEGID_SYSTEM; AuditParameters.AuditId = SE_AUDITID_AUDITS_DISCARDED; AuditParameters.Type = EVENTLOG_AUDIT_SUCCESS; AuditParameters.ParameterCount = 0; LsapSetParmTypeSid( AuditParameters, AuditParameters.ParameterCount, LsapLocalSystemSid ); AuditParameters.ParameterCount++; LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LsapSubsystemName ); AuditParameters.ParameterCount++; LsapSetParmTypeUlong( AuditParameters, AuditParameters.ParameterCount, NumberOfEventsDiscarded ); AuditParameters.ParameterCount++; ( VOID ) LsapAdtWriteLog( &AuditParameters, 0 ); return; } 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; PLUID *FilterPrivilege = NULL; ULONG i; SE_ADT_PARAMETER_ARRAY AuditParameters; if ( !LsapAdtEventsInformation.AuditingMode ) { return; } if (!(LsapAdtEventsInformation.EventAuditingOptions[AuditCategoryPrivilegeUse] & POLICY_AUDIT_EVENT_SUCCESS)) { return; } if ( (Privileges == NULL) || (Privileges->PrivilegeCount == 0) ) { return; } // // We can't need any more space than what's being passed in. // Buffer = (PPRIVILEGE_SET)LsapAllocateLsaHeap( LsapPrivilegeSetSize( Privileges ) ); if ( Buffer == NULL ) { // // ISSUE-2000/09/26-kumarp : call LsapAuditFailed // return; } 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 ) { LsapFreeLsaHeap( Buffer ); return; } // // 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, 0 ); 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. --*/ { SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; NTSTATUS Status; SE_ADT_PARAMETER_ARRAY AuditParameters; if ( !LsapAdtEventsInformation.AuditingMode ) { return; } if (!(LsapAdtEventsInformation.EventAuditingOptions[AuditCategorySystem] & POLICY_AUDIT_EVENT_SUCCESS)) { return; } 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, 0 ); 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. --*/ { SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; NTSTATUS Status; ANSI_STRING AnsiString; UNICODE_STRING Unicode; PSZ LogonProcessNameBuffer; SE_ADT_PARAMETER_ARRAY AuditParameters; if ( !LsapAdtEventsInformation.AuditingMode ) { return; } if (!(LsapAdtEventsInformation.EventAuditingOptions[AuditCategorySystem] & POLICY_AUDIT_EVENT_SUCCESS)) { return; } // // Turn the name text in the ConnectInfo structure into // something we can work with. // LogonProcessNameBuffer = (PSZ)LsapAllocateLsaHeap( ConnectInfo->LogonProcessNameLength+1 ); if ( LogonProcessNameBuffer == NULL ) { return; } RtlCopyMemory( LogonProcessNameBuffer, ConnectInfo->LogonProcessName, ConnectInfo->LogonProcessNameLength ); LogonProcessNameBuffer[ConnectInfo->LogonProcessNameLength] = 0; RtlInitAnsiString( &AnsiString, LogonProcessNameBuffer ); Status = RtlAnsiStringToUnicodeString( &Unicode, &AnsiString, TRUE ); if ( !NT_SUCCESS( Status )) { // // Must be out of memory, not much we can do here // LsapFreeLsaHeap( LogonProcessNameBuffer ); return; } 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, 0 ); 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; if(!AuditEventsInfo->AuditingMode) { return; } if (!((AuditEventsInfo->EventAuditingOptions)[AuditCategorySystem] & POLICY_AUDIT_EVENT_SUCCESS )) { return; } // // 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 (if available) // LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &LsapSubsystemName ); AuditParameters.ParameterCount++; ( VOID ) LsapAdtWriteLog( &AuditParameters, 0 ); 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 ) /*++ Routine Description: Generates an audit of a logon event as appropriate. Arguments: Return Value: None. --*/ { NTSTATUS Status = STATUS_SUCCESS; UNICODE_STRING SpareString; UNICODE_STRING AuthenticationIdString = { 0 }; BOOLEAN FreeWhenDone = FALSE; SE_ADT_PARAMETER_ARRAY AuditParameters; BOOLEAN AuditingSuccess; BOOLEAN AuditingFailure; PSID pSid; PLSAP_LOGON_SESSION pLogonSession = NULL; RtlInitUnicodeString( &SpareString, L"Security"); AuditingFailure = (EventType == EVENTLOG_AUDIT_FAILURE) && LsapAuditFailedLogons; AuditingSuccess = (EventType == EVENTLOG_AUDIT_SUCCESS) && LsapAuditSuccessfulLogons; // // return quickly if auditing is not enabled // if ( !(AuditingFailure || AuditingSuccess) ) { 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 (if available) // LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, &SpareString ); AuditParameters.ParameterCount++; // // Account name // if ( ARGUMENT_PRESENT( AccountName ) ) { LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, AccountName ); } AuditParameters.ParameterCount++; // // Authenticating Authority (domain name) // if ( ARGUMENT_PRESENT( AuthenticatingAuthority ) ) { LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, AuthenticatingAuthority ); } 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 )) { LsapSetParmTypeString( AuditParameters, AuditParameters.ParameterCount, WorkstationName ); } 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++; } ( VOID ) LsapAdtWriteLog( &AuditParameters, 0 ); 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 ); } 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 ) /*++ 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 should be the client machine. UserSid - Sid for the logged on account. LogonType - Type of logon, such as Network, Interactive, Service, 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. currently this is supported only by the kerberos package. 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; 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 ); } 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; } 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 ); ( VOID ) LsapAdtWriteLog( &AuditParameters, 0 ); Cleanup: if (fFreeLogonId) { LsapFreeLsaHeap(usLogonId.Buffer); } }