1457 lines
37 KiB
1457 lines
37 KiB
//+-----------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (c) Microsoft Corporation 2000
|
|
//
|
|
// File: A D T G E N P . C
|
|
//
|
|
// Contents: definitions of types/functions required for
|
|
// generating generic audits.
|
|
//
|
|
//
|
|
// History:
|
|
// 07-January-2000 kumarp created
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
#include <lsapch2.h>
|
|
#pragma hdrstop
|
|
|
|
#include "adtp.h"
|
|
#include "adtgen.h"
|
|
#include "adtgenp.h"
|
|
|
|
// temp - gregjohn 5/17/02 - to be removed as soon as base changes to msaudite.h migrate to lab03
|
|
#ifndef SE_AUDITID_REPLICA_LINGERING_OBJECT_REMOVAL
|
|
#define SE_AUDITID_REPLICA_LINGERING_OBJECT_REMOVAL ((ULONG)0x00000349L)
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------
|
|
//
|
|
// globals
|
|
//
|
|
|
|
//
|
|
// critsec that guards access to
|
|
// LsapAdtContextList and LsapAdtContextListCount
|
|
//
|
|
|
|
RTL_CRITICAL_SECTION LsapAdtContextListLock;
|
|
|
|
//
|
|
// linked list of audit contexts. see comment in fn LsapAdtAddAuditContext
|
|
//
|
|
|
|
LIST_ENTRY LsapAdtContextList;
|
|
|
|
//
|
|
// number of elements in the context list
|
|
//
|
|
|
|
ULONG LsapAdtContextListCount=0;
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
//
|
|
// helper macros
|
|
//
|
|
|
|
#define LockAuditContextList() RtlEnterCriticalSection(&LsapAdtContextListLock)
|
|
|
|
|
|
#define UnLockAuditContextList() RtlLeaveCriticalSection(&LsapAdtContextListLock)
|
|
|
|
|
|
//
|
|
// convert a context handle to a context pointer
|
|
//
|
|
|
|
#define AdtpContextPtrFromHandle(h) ((AUDIT_CONTEXT*) (h))
|
|
#define AdtpContextHandleFromptr(p) ((AUDIT_HANDLE) (p))
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
//
|
|
// internal routines
|
|
//
|
|
|
|
NTSTATUS
|
|
LsapAdtIsValidAuditInfo(
|
|
IN PAUTHZ_AUDIT_EVENT_TYPE_OLD pAuditEventType
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAdtIsValidAuditContext(
|
|
IN AUDIT_HANDLE hAudit
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAdtIsContextInList(
|
|
IN AUDIT_HANDLE hAudit
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapGetAuditEventParams(
|
|
IN PAUTHZ_AUDIT_EVENT_TYPE_OLD pAuditEventType,
|
|
OUT PAUDIT_CONTEXT pAuditContext
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAdtAddAuditContext(
|
|
IN AUDIT_HANDLE hAudit
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAdtDeleteAuditContext(
|
|
IN AUDIT_HANDLE hAudit
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAdtFreeAuditContext(
|
|
AUDIT_HANDLE hAudit
|
|
);
|
|
|
|
BOOLEAN
|
|
LsapAdtIsValidAuthzAuditId(
|
|
IN USHORT AuditId
|
|
);
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtInitGenericAudits( VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the generic audit functionality.
|
|
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
InitializeListHead( &LsapAdtContextList );
|
|
LsapAdtContextListCount = 0;
|
|
|
|
Status = RtlInitializeCriticalSection(&LsapAdtContextListLock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapRegisterAuditEvent(
|
|
IN PAUTHZ_AUDIT_EVENT_TYPE_OLD pAuditEventType,
|
|
OUT AUDIT_HANDLE* phAudit
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Register the specified event;
|
|
generate and return an audit context.
|
|
|
|
|
|
Arguments:
|
|
|
|
pAuditEventType - pointer to audit event info. This param describes
|
|
the type of event to be registered.
|
|
|
|
phAudit - pointer to audit context returned
|
|
this handle must be freed by calling
|
|
LsaUnregisterAuditEvent when no longer needed.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
Notes:
|
|
Note that this function does NOT register the schema of an event. It is
|
|
assumed that the schema has been registered *before* calling
|
|
this function.
|
|
|
|
The generated context is stored in LsapAdtContextList.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PAUDIT_CONTEXT pAuditContext=NULL;
|
|
UINT RpcTransportType;
|
|
RPC_STATUS RpcStatus;
|
|
|
|
*phAudit = NULL;
|
|
|
|
//
|
|
// find out the transport over which we are receiving this call
|
|
//
|
|
|
|
RpcStatus = I_RpcBindingInqTransportType ( NULL, &RpcTransportType );
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
Status = I_RpcMapWin32Status( RpcStatus );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// if the transport is anything other than LPC, error out
|
|
// we want to support only LPC for audit calls
|
|
//
|
|
|
|
if ( RpcTransportType != TRANSPORT_TYPE_LPC )
|
|
{
|
|
Status = RPC_NT_PROTSEQ_NOT_SUPPORTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// do a sanity check on the audit-info supplied
|
|
//
|
|
|
|
Status = LsapAdtIsValidAuditInfo( pAuditEventType );
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// make sure that the caller has audit privilege
|
|
// (LsapAdtCheckAuditPrivilege calls RpcImpersonateClient)
|
|
//
|
|
#ifndef SE_ADT_NO_AUDIT_PRIVILEGE_CHECK
|
|
Status = LsapAdtCheckAuditPrivilege();
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
|
|
pAuditContext =
|
|
(PAUDIT_CONTEXT) LsapAllocateLsaHeap( sizeof(AUDIT_CONTEXT) );
|
|
|
|
if (pAuditContext)
|
|
{
|
|
//
|
|
// store the parameters for this audit into the
|
|
// generated context.
|
|
//
|
|
|
|
Status = LsapGetAuditEventParams(pAuditEventType, pAuditContext);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// add to context list
|
|
//
|
|
|
|
Status = LsapAdtAddAuditContext(
|
|
AdtpContextHandleFromptr( pAuditContext ) );
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*phAudit = AdtpContextHandleFromptr( pAuditContext );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
Cleanup:
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
LsapFreeLsaHeap(pAuditContext);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapGenAuditEvent(
|
|
IN AUDIT_HANDLE hAudit,
|
|
IN DWORD dwFlags,
|
|
IN PAUDIT_PARAMS pAuditParams,
|
|
IN PVOID pReserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Publish the specified audit event.
|
|
|
|
|
|
Arguments:
|
|
|
|
hAudit - handle of audit-context previously obtained
|
|
by calling LsaRegisterAuditEvent
|
|
|
|
dwFlags - TBD
|
|
|
|
pAuditParams - pointer to event parameters. This structure should
|
|
be initialized using AuthzInitAuditParams.
|
|
Please see detailed comment on that function
|
|
in adtutil.c on usage of this parameter.
|
|
|
|
pReserved - reserved
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -- on success
|
|
STATUS_INVALID_PARAMETER -- if one or more params are invalid
|
|
STATUS_AUDITING_DISABLED -- if the event being generated is not
|
|
being audited because the policy setting
|
|
is disabled.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PAUDIT_CONTEXT pAuditContext;
|
|
SE_ADT_PARAMETER_ARRAY SeAuditParameters = { 0 };
|
|
UNICODE_STRING Strings[SE_MAX_AUDIT_PARAM_STRINGS] = { 0 };
|
|
BOOLEAN bAudit;
|
|
SE_ADT_OBJECT_TYPE ObjectTypes[MAX_OBJECT_TYPES];
|
|
PSE_ADT_OBJECT_TYPE pObjectTypes = ObjectTypes;
|
|
UINT AuditEventType;
|
|
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
UNREFERENCED_PARAMETER(pReserved);
|
|
|
|
DsysAssertMsg( pAuditParams != NULL, "LsapGenAuditEvent" );
|
|
|
|
//
|
|
// make sure that the context is in our list
|
|
//
|
|
|
|
Status = LsapAdtIsContextInList( hAudit );
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// verify that the context is not invalid
|
|
//
|
|
|
|
Status = LsapAdtIsValidAuditContext( hAudit );
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
pAuditContext = AdtpContextPtrFromHandle( hAudit );
|
|
|
|
//
|
|
// return error if the context and the passed parameters
|
|
// do not agree on the number of parameters
|
|
//
|
|
|
|
if ( pAuditContext->ParameterCount != pAuditParams->Count )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( pAuditParams->Flags & APF_AuditSuccess )
|
|
{
|
|
AuditEventType = EVENTLOG_AUDIT_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
AuditEventType = EVENTLOG_AUDIT_FAILURE;
|
|
}
|
|
|
|
//
|
|
// check if auditing is enabled for that category
|
|
//
|
|
|
|
Status = LsapAdtAuditingEnabledBySid(
|
|
LsapAdtEventTypeFromCategoryId(pAuditContext->CategoryId),
|
|
(PSID)pAuditParams->Parameters[0].Data0,
|
|
AuditEventType,
|
|
&bAudit
|
|
);
|
|
|
|
if (NT_SUCCESS(Status) && bAudit)
|
|
{
|
|
SeAuditParameters.Type = (USHORT) AuditEventType;
|
|
SeAuditParameters.CategoryId = pAuditContext->CategoryId;
|
|
SeAuditParameters.AuditId = pAuditContext->AuditId;
|
|
SeAuditParameters.ParameterCount = pAuditParams->Count;
|
|
|
|
//
|
|
// Map AUDIT_PARAMS structure to SE_ADT_PARAMETER_ARRAY structure
|
|
//
|
|
|
|
Status = LsapAdtMapAuditParams( pAuditParams,
|
|
&SeAuditParameters,
|
|
(PUNICODE_STRING) Strings,
|
|
&pObjectTypes );
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// write the params to eventlog
|
|
//
|
|
|
|
Status = LsapAdtWriteLog( &SeAuditParameters );
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// crash on failure if specified by the security policy
|
|
//
|
|
// But do not crash on documented errors
|
|
//
|
|
|
|
if ( ( Status != STATUS_INVALID_PARAMETER ) &&
|
|
( Status != STATUS_AUDITING_DISABLED ) &&
|
|
( Status != STATUS_NOT_FOUND ) )
|
|
{
|
|
LsapAuditFailed( Status );
|
|
}
|
|
}
|
|
|
|
//
|
|
// to save the cost of heap alloc/dealloc each time for
|
|
// the object types. we use a fixed array of size MAX_OBJECT_TYPES
|
|
// If this size is not enough, LsapAdtMapAuditParams will allocate
|
|
// a bigger array, in this case the following condition
|
|
// becomes true and we free the allocated array.
|
|
//
|
|
|
|
if ( pObjectTypes && ( pObjectTypes != ObjectTypes ))
|
|
{
|
|
LsapFreeLsaHeap( pObjectTypes );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapUnregisterAuditEvent(
|
|
IN OUT AUDIT_HANDLE* phAudit
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unregister the specified context and free up any resources.
|
|
|
|
Arguments:
|
|
|
|
hAudit - handle of audit context to unregister
|
|
This is set to NULL when the call returns.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
//
|
|
// remove it from the list and free up resources
|
|
//
|
|
|
|
if ( phAudit )
|
|
{
|
|
Status = LsapAdtDeleteAuditContext( *phAudit );
|
|
|
|
*phAudit = NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapGetAuditEventParams(
|
|
IN PAUTHZ_AUDIT_EVENT_TYPE_OLD pAuditEventType,
|
|
OUT PAUDIT_CONTEXT pAuditContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the audit context using information in the
|
|
passed pAuditEventType
|
|
|
|
Arguments:
|
|
|
|
pAuditEventType - pointer to audit event info
|
|
|
|
pAuditContext - pointer to audit context to be initialzed
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if params are ok
|
|
STATUS_INVALID_PARAMETER otherwise
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
USHORT CategoryId;
|
|
USHORT AuditId;
|
|
USHORT ParameterCount;
|
|
ULONG ProcessId = 0xffffffff;
|
|
LUID LinkId;
|
|
RPC_STATUS RpcStatus;
|
|
UINT ClientIsLocal = 0;
|
|
|
|
DsysAssertMsg( pAuditContext != NULL, "LsapGetAuditEventParams" );
|
|
|
|
if (pAuditEventType &&
|
|
(pAuditEventType->Version == AUDIT_TYPE_LEGACY))
|
|
{
|
|
CategoryId = pAuditEventType->u.Legacy.CategoryId;
|
|
AuditId = pAuditEventType->u.Legacy.AuditId;
|
|
ParameterCount = pAuditEventType->u.Legacy.ParameterCount;
|
|
LinkId = pAuditEventType->LinkId;
|
|
|
|
RpcStatus = I_RpcBindingIsClientLocal( 0, &ClientIsLocal );
|
|
|
|
if ( ( RpcStatus == RPC_S_OK ) && ClientIsLocal )
|
|
{
|
|
RpcStatus = I_RpcBindingInqLocalClientPID( NULL, &ProcessId );
|
|
|
|
#if DBG
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
DbgPrint("LsapGetAuditEventParams: I_RpcBindingInqLocalClientPID: %lx\n", RpcStatus);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// for now, do not let events to be published under other categories
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// currently we support only the legacy audits
|
|
//
|
|
|
|
pAuditContext->Flags = ACF_LegacyAudit;
|
|
pAuditContext->CategoryId = CategoryId;
|
|
pAuditContext->AuditId = AuditId;
|
|
pAuditContext->ParameterCount = ParameterCount;
|
|
pAuditContext->LinkId = LinkId;
|
|
pAuditContext->ProcessId = ProcessId;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtIsContextInList(
|
|
IN AUDIT_HANDLE hAudit
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Lookup the specified context in our list
|
|
|
|
Arguments:
|
|
|
|
hAudit - handle of audit context to lookup
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
STATUS_SUCCESS if found
|
|
STATUS_NOT_FOUND if not found
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_NOT_FOUND;
|
|
PAUDIT_CONTEXT pAuditContext, pContext;
|
|
PLIST_ENTRY Scan;
|
|
#if DBG
|
|
LONG ContextCount = (LONG) LsapAdtContextListCount;
|
|
#endif
|
|
|
|
pAuditContext = AdtpContextPtrFromHandle( hAudit );
|
|
|
|
Status = LockAuditContextList();
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Scan = LsapAdtContextList.Flink;
|
|
|
|
while ( Scan != &LsapAdtContextList )
|
|
{
|
|
#if DBG
|
|
//
|
|
// make sure that the ContextCount does not become <= 0
|
|
// before the list runs out.
|
|
//
|
|
|
|
DsysAssertMsg( ContextCount > 0, "LsapAdtIsContextInList: list may be corrupt!" );
|
|
ContextCount--;
|
|
#endif
|
|
|
|
pContext = CONTAINING_RECORD( Scan, AUDIT_CONTEXT, Link );
|
|
|
|
if ( pAuditContext == pContext )
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
Scan = Scan->Flink;
|
|
}
|
|
#if DBG
|
|
//
|
|
// if we didnt find the item then we must have traversed
|
|
// the whole list. in this case, make sure that the
|
|
// LsapAdtContextListCount is in sync with the list
|
|
//
|
|
|
|
if ( Status == STATUS_NOT_FOUND )
|
|
{
|
|
DsysAssertMsg( ContextCount == 0, "LsapAdtIsContextInList: list may be corrupt!" );
|
|
}
|
|
#endif
|
|
UnLockAuditContextList();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtAddAuditContext(
|
|
IN AUDIT_HANDLE hAudit
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Insert the specified context in our list
|
|
|
|
Arguments:
|
|
|
|
hAudit - handle of audit context to insert
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
Notes:
|
|
|
|
Currently we store the audit contexts in a linked list.
|
|
This is ok since we do not expect more than 5 to 10 contexts
|
|
in the list. Later on when the generic audit interface is
|
|
to be published, we can change this to a more efficient storage.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PAUDIT_CONTEXT pAuditContext;
|
|
|
|
DsysAssertMsg( LsapAdtIsValidAuditContext( hAudit ) == STATUS_SUCCESS,
|
|
"LsapAdtAddAuditContext" );
|
|
|
|
pAuditContext = AdtpContextPtrFromHandle( hAudit );
|
|
|
|
Status = LockAuditContextList();
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
LsapAdtContextListCount++;
|
|
InsertTailList(&LsapAdtContextList, &pAuditContext->Link);
|
|
|
|
UnLockAuditContextList();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtDeleteAuditContext(
|
|
IN AUDIT_HANDLE hAudit
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove a context from our list and free resources.
|
|
|
|
Arguments:
|
|
|
|
hAudit - handle of audit context to remove
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
STATUS_SUCCESS on success
|
|
STATUS_NOT_FOUND if context is not found
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PAUDIT_CONTEXT pAuditContext;
|
|
|
|
DsysAssertMsg( LsapAdtIsValidAuditContext( hAudit ) == STATUS_SUCCESS,
|
|
"LsapAdtDeleteAuditContext" );
|
|
|
|
Status = LockAuditContextList();
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = LsapAdtIsContextInList( hAudit );
|
|
|
|
DsysAssertMsg( Status != STATUS_NOT_FOUND,
|
|
"LsapAdtDeleteAuditContext: trying to del unknown context" );
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
pAuditContext = AdtpContextPtrFromHandle( hAudit );
|
|
|
|
RemoveEntryList( &pAuditContext->Link );
|
|
LsapAdtContextListCount--;
|
|
|
|
DsysAssertMsg(((LONG) LsapAdtContextListCount) >= 0,
|
|
"LsapAdtContextListCount should never be negative!");
|
|
}
|
|
|
|
UnLockAuditContextList();
|
|
|
|
(VOID) LsapAdtFreeAuditContext( hAudit );
|
|
}
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtIsValidAuditInfo(
|
|
IN PAUTHZ_AUDIT_EVENT_TYPE_OLD pAuditEventType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify AUTHZ_AUDIT_EVENT_INFO structure members
|
|
|
|
Arguments:
|
|
|
|
pAuditEventType - pointer to AUTHZ_AUDIT_EVENT_TYPE_OLD
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if info is within acceptable values
|
|
STATUS_INVALID_PARAMETER if not
|
|
|
|
Notes:
|
|
|
|
Currently the validity of the parameters is judged using
|
|
the boundaries defined in msaudite.mc file.
|
|
|
|
This function will need to be amended when we allow third party
|
|
apps to supply audit events.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if ( ( pAuditEventType->Version == AUDIT_TYPE_LEGACY ) &&
|
|
IsValidCategoryId( pAuditEventType->u.Legacy.CategoryId ) &&
|
|
IsValidAuditId( pAuditEventType->u.Legacy.AuditId ) &&
|
|
LsapAdtIsValidAuthzAuditId( pAuditEventType->u.Legacy.AuditId ) &&
|
|
IsValidParameterCount( pAuditEventType->u.Legacy.ParameterCount ) )
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
LsapAdtIsValidAuthzAuditId(
|
|
IN USHORT AuditId
|
|
)
|
|
|
|
/**
|
|
|
|
Routine Description
|
|
This examines the audit id and determines if authz should be generating this type
|
|
of audit.
|
|
|
|
Arguments
|
|
AuditId - the audit to query.
|
|
|
|
Return Value
|
|
Boolean.
|
|
|
|
**/
|
|
|
|
{
|
|
static ULONG ValidAuthzAuditIdArray[] = {
|
|
|
|
//
|
|
// generated by all users of AuthzAccessCheck
|
|
//
|
|
SE_AUDITID_OBJECT_OPERATION,
|
|
|
|
//
|
|
// Generic audit
|
|
//
|
|
SE_AUDITID_GENERIC_AUDIT_EVENT,
|
|
|
|
//
|
|
// generated by cert server
|
|
//
|
|
SE_AUDITID_CERTSRV_DENYREQUEST,
|
|
SE_AUDITID_CERTSRV_RESUBMITREQUEST,
|
|
SE_AUDITID_CERTSRV_REVOKECERT,
|
|
SE_AUDITID_CERTSRV_PUBLISHCRL,
|
|
SE_AUDITID_CERTSRV_AUTOPUBLISHCRL,
|
|
SE_AUDITID_CERTSRV_SETEXTENSION,
|
|
SE_AUDITID_CERTSRV_SETATTRIBUTES,
|
|
SE_AUDITID_CERTSRV_SHUTDOWN,
|
|
SE_AUDITID_CERTSRV_BACKUPSTART,
|
|
SE_AUDITID_CERTSRV_BACKUPEND,
|
|
SE_AUDITID_CERTSRV_RESTORESTART,
|
|
SE_AUDITID_CERTSRV_RESTOREEND,
|
|
SE_AUDITID_CERTSRV_SERVICESTART,
|
|
SE_AUDITID_CERTSRV_SERVICESTOP,
|
|
SE_AUDITID_CERTSRV_SETSECURITY,
|
|
SE_AUDITID_CERTSRV_GETARCHIVEDKEY,
|
|
SE_AUDITID_CERTSRV_IMPORTCERT,
|
|
SE_AUDITID_CERTSRV_SETAUDITFILTER,
|
|
SE_AUDITID_CERTSRV_NEWREQUEST,
|
|
SE_AUDITID_CERTSRV_REQUESTAPPROVED,
|
|
SE_AUDITID_CERTSRV_REQUESTDENIED,
|
|
SE_AUDITID_CERTSRV_REQUESTPENDING,
|
|
SE_AUDITID_CERTSRV_SETOFFICERRIGHTS,
|
|
SE_AUDITID_CERTSRV_SETCONFIGENTRY,
|
|
SE_AUDITID_CERTSRV_SETCAPROPERTY,
|
|
SE_AUDITID_CERTSRV_KEYARCHIVED,
|
|
SE_AUDITID_CERTSRV_IMPORTKEY,
|
|
SE_AUDITID_CERTSRV_PUBLISHCACERT,
|
|
SE_AUDITID_CERTSRV_DELETEROW,
|
|
SE_AUDITID_CERTSRV_ROLESEPARATIONSTATE,
|
|
|
|
//
|
|
// generated by termsrv
|
|
//
|
|
SE_AUDITID_SESSION_RECONNECTED,
|
|
SE_AUDITID_SESSION_DISCONNECTED,
|
|
|
|
//
|
|
// generated by winlogon
|
|
//
|
|
SE_AUDITID_BEGIN_LOGOFF,
|
|
|
|
//
|
|
// generated by scm
|
|
//
|
|
SE_AUDITID_SERVICE_INSTALL,
|
|
|
|
//
|
|
// generated by AzManager
|
|
//
|
|
SE_AUDITID_AZ_APPLICATION_INITIALIZATION,
|
|
SE_AUDITID_AZ_CLIENTCONTEXT_CREATION,
|
|
SE_AUDITID_AZ_CLIENTCONTEXT_DELETION,
|
|
SE_AUDITID_AZ_ACCESSCHECK,
|
|
|
|
//
|
|
// generated by task scheduler
|
|
//
|
|
SE_AUDITID_JOB_CREATED,
|
|
|
|
//
|
|
// generated by AD replication
|
|
//
|
|
SE_AUDITID_REPLICA_DEST_NC_MODIFIED,
|
|
SE_AUDITID_REPLICA_OBJ_ATTR_REPLICATION,
|
|
SE_AUDITID_REPLICA_SOURCE_NC_ESTABLISHED,
|
|
SE_AUDITID_REPLICA_SOURCE_NC_MODIFIED,
|
|
SE_AUDITID_REPLICA_SOURCE_NC_REMOVED,
|
|
SE_AUDITID_REPLICA_SOURCE_NC_SYNC_BEGINS,
|
|
SE_AUDITID_REPLICA_SOURCE_NC_SYNC_ENDS,
|
|
SE_AUDITID_REPLICA_FAILURE_EVENT_BEGIN,
|
|
SE_AUDITID_REPLICA_FAILURE_EVENT_END,
|
|
SE_AUDITID_REPLICA_LINGERING_OBJECT_REMOVAL
|
|
|
|
};
|
|
|
|
ULONG ValidAuditIdCount = sizeof(ValidAuthzAuditIdArray) / sizeof(ULONG);
|
|
ULONG i;
|
|
|
|
//
|
|
// This is a hack: we know that TS generates a shutdown audit when they
|
|
// shouldn't. However, we don't want to assert since they are not fixing
|
|
// their code until LongHorn.
|
|
//
|
|
|
|
if (AuditId == SE_AUDITID_SYSTEM_SHUTDOWN)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < ValidAuditIdCount; i++)
|
|
{
|
|
if (ValidAuthzAuditIdArray[i] == AuditId)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
ASSERT(L"Authz has attempted to generate a disallowed audit." && FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtIsValidAuditContext(
|
|
IN AUDIT_HANDLE hAudit
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify that the specified context has valid info
|
|
|
|
Arguments:
|
|
|
|
hAudit - handle of context to verify
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if info is within acceptable values
|
|
STATUS_INVALID_PARAMETER if not
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
PAUDIT_CONTEXT pAuditContext;
|
|
|
|
pAuditContext = AdtpContextPtrFromHandle( hAudit );
|
|
|
|
if ( pAuditContext &&
|
|
( pAuditContext->Flags & ACF_LegacyAudit ) &&
|
|
!( pAuditContext->Flags & ~ACF_ValidFlags ) &&
|
|
IsValidCategoryId( pAuditContext->CategoryId ) &&
|
|
IsValidAuditId( pAuditContext->AuditId ) &&
|
|
IsValidParameterCount( pAuditContext->ParameterCount ) )
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtMapAuditParams(
|
|
IN PAUDIT_PARAMS pAuditParams,
|
|
OUT PSE_ADT_PARAMETER_ARRAY pSeAuditParameters,
|
|
OUT PUNICODE_STRING pString,
|
|
OUT PSE_ADT_OBJECT_TYPE* ppObjectTypeList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map AUDIT_PARAMS structure to SE_ADT_PARAMETER_ARRAY structure.
|
|
|
|
Arguments:
|
|
|
|
pAuditParams - pointer to input audit params
|
|
|
|
pSeAuditParameters - pointer to output audit params to be initialized.
|
|
The max allowed size of Parameters member of
|
|
this structure is determined by the value of
|
|
SE_MAX_AUDIT_PARAMETERS.
|
|
Caller needs to allocate memory for this param.
|
|
|
|
pString - pointer to temp strings used in the mapping.
|
|
The max size of this structure is limited by
|
|
value of SE_MAX_AUDIT_PARAM_STRINGS.
|
|
Caller needs to allocate memory for this param.
|
|
|
|
ppObjectTypeList - pointer to object type list.
|
|
This function assumes that the size of this param
|
|
is MAX_OBJECT_TYPES upon entry. If more object types
|
|
are to be mapped, this function will alloc memory
|
|
using LsapAllocateLsaHeap. When this function
|
|
returns, the caller needs to check if the value of
|
|
this param is different from that when called.
|
|
If so, it should free this using LsapFreeLsaHeap.
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS on success
|
|
STATUS_INVALID_PARAMETER if one or more params are invalid
|
|
STATUS_BUFFER_OVERFLOW if the number of strings generated exceeds
|
|
SE_MAX_AUDIT_PARAM_STRINGS
|
|
STATUS_NO_MEMORY if out of memory
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
UINT i=0;
|
|
USHORT j=0;
|
|
AUDIT_PARAM* pInParam;
|
|
SE_ADT_PARAMETER_ARRAY_ENTRY* pOutParam;
|
|
USHORT IndexMap[SE_MAX_AUDIT_PARAMETERS];
|
|
USHORT ObjectTypeIndex;
|
|
LUID LogonId;
|
|
FILETIME FileTime;
|
|
ULONGLONG Qword;
|
|
AUDIT_OBJECT_TYPES* pInObjectTypes;
|
|
USHORT NumObjectTypes;
|
|
USHORT NumStringsUsed=0;
|
|
BOOL fObjectTypeListAllocated=FALSE;
|
|
|
|
DsysAssertMsg(!(pAuditParams->Flags & (~APF_ValidFlags)),
|
|
"LsapAdtMapAuditParams");
|
|
DsysAssertMsg(pAuditParams->Count <= SE_MAX_AUDIT_PARAMETERS,
|
|
"LsapAdtMapAuditParams");
|
|
DsysAssertMsg(pAuditParams->Parameters != NULL, "LsapAdtMapAuditParams");
|
|
DsysAssertMsg(pString != NULL, "LsapAdtMapAuditParams");
|
|
DsysAssertMsg(ppObjectTypeList != NULL, "LsapAdtMapAuditParams");
|
|
|
|
pInParam = pAuditParams->Parameters;
|
|
pOutParam = pSeAuditParameters->Parameters;
|
|
|
|
|
|
for (i=0; i < pAuditParams->Count; i++, j++, pInParam++, pOutParam++ )
|
|
{
|
|
//
|
|
// the index-map maps input parameters to the corresponding
|
|
// output parameters. currently there is only 1-1 mapping
|
|
// thus (i == j) is always true.
|
|
//
|
|
|
|
IndexMap[i] = j;
|
|
|
|
switch(pInParam->Type)
|
|
{
|
|
default:
|
|
case APT_None:
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
|
|
//
|
|
// the input params have null-terminated string
|
|
// convert it to UNICODE_STRING. Use the passed
|
|
// pString array to hold the converted strings.
|
|
// A string is either just a string or a file spec.
|
|
//
|
|
|
|
case APT_String:
|
|
DsysAssertMsg( pInParam->Data0, "APT_String" );
|
|
|
|
if (pInParam->Flags & AP_Filespec)
|
|
{
|
|
pOutParam->Type = SeAdtParmTypeFileSpec;
|
|
}
|
|
else
|
|
{
|
|
pOutParam->Type = SeAdtParmTypeString;
|
|
}
|
|
|
|
RtlInitUnicodeString( pString, (PCWSTR) pInParam->Data0 );
|
|
pOutParam->Length = sizeof(UNICODE_STRING) + pString->Length;
|
|
pOutParam->Address = pString++;
|
|
NumStringsUsed++;
|
|
|
|
//
|
|
// the passed array has limited size
|
|
//
|
|
|
|
if ( NumStringsUsed >= SE_MAX_AUDIT_PARAM_STRINGS )
|
|
{
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Convert a Ulong. It can be mapped to
|
|
// any one of the following:
|
|
// - access-mask
|
|
// - decimal ulong
|
|
// - hex ulong
|
|
//
|
|
|
|
case APT_Ulong:
|
|
pOutParam->Data[0] = pInParam->Data0;
|
|
pOutParam->Length = sizeof(ULONG);
|
|
if ( pInParam->Flags & AP_AccessMask )
|
|
{
|
|
pOutParam->Type = SeAdtParmTypeAccessMask;
|
|
ObjectTypeIndex = (USHORT) pInParam->Data1;
|
|
|
|
//
|
|
// the index cannot be greater than the current item
|
|
//
|
|
|
|
if (ObjectTypeIndex >= i)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
ObjectTypeIndex = IndexMap[ObjectTypeIndex];
|
|
pOutParam->Data[1] = ObjectTypeIndex;
|
|
}
|
|
else
|
|
{
|
|
if ( pInParam->Flags & AP_FormatHex )
|
|
{
|
|
pOutParam->Type = SeAdtParmTypeHexUlong;
|
|
}
|
|
else
|
|
{
|
|
pOutParam->Type = SeAdtParmTypeUlong;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case APT_Sid:
|
|
{
|
|
PSID pSid;
|
|
|
|
DsysAssertMsg( pInParam->Data0, "APT_Sid" );
|
|
|
|
pOutParam->Type = SeAdtParmTypeSid;
|
|
pSid = (PSID) pInParam->Data0;
|
|
|
|
if ( !RtlValidSid( pSid ) )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
pOutParam->Address = pSid;
|
|
pOutParam->Length = RtlLengthSid( pSid );
|
|
}
|
|
break;
|
|
|
|
case APT_Guid:
|
|
DsysAssertMsg( pInParam->Data0, "APT_Guid" );
|
|
|
|
if ( !pInParam->Data0 )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
pOutParam->Type = SeAdtParmTypeGuid;
|
|
pOutParam->Address = (PVOID) pInParam->Data0;
|
|
pOutParam->Length = sizeof(GUID);
|
|
break;
|
|
|
|
case APT_LogonId:
|
|
pOutParam->Type = SeAdtParmTypeLogonId;
|
|
LogonId.LowPart = (ULONG) pInParam->Data0;
|
|
LogonId.HighPart = ( LONG) pInParam->Data1;
|
|
*((LUID*) pOutParam->Data) = LogonId;
|
|
pOutParam->Length = sizeof(LUID);
|
|
break;
|
|
|
|
case APT_Luid:
|
|
pOutParam->Type = SeAdtParmTypeLuid;
|
|
LogonId.LowPart = (ULONG) pInParam->Data0;
|
|
LogonId.HighPart = ( LONG) pInParam->Data1;
|
|
*((LUID*) pOutParam->Data) = LogonId;
|
|
pOutParam->Length = sizeof(LUID);
|
|
break;
|
|
|
|
case APT_Pointer:
|
|
pOutParam->Type = SeAdtParmTypePtr;
|
|
pOutParam->Data[0] = pInParam->Data0;
|
|
pOutParam->Length = sizeof(PVOID);
|
|
break;
|
|
|
|
case APT_ObjectTypeList:
|
|
pInObjectTypes = (AUDIT_OBJECT_TYPES*) pInParam->Data0;
|
|
NumObjectTypes = pInObjectTypes->Count;
|
|
|
|
DsysAssertMsg( pInObjectTypes, "APT_ObjectTypeList" );
|
|
DsysAssertMsg( NumObjectTypes, "APT_ObjectTypeList" );
|
|
|
|
if ( !pInObjectTypes )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if ( !NumObjectTypes )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// get the type of the objects from Data1
|
|
//
|
|
|
|
ObjectTypeIndex = (USHORT) pInParam->Data1;
|
|
|
|
//
|
|
// the index cannot be greater than the current item
|
|
//
|
|
|
|
if (ObjectTypeIndex >= i)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
ObjectTypeIndex = IndexMap[ObjectTypeIndex];
|
|
|
|
pOutParam->Type = SeAdtParmTypeObjectTypes;
|
|
pOutParam->Length = NumObjectTypes * sizeof(SE_ADT_OBJECT_TYPE);
|
|
|
|
//
|
|
// the caller passes us a fixed sized object-type array
|
|
// if that is not big enough, allocate a new one
|
|
//
|
|
|
|
if ( NumObjectTypes > MAX_OBJECT_TYPES )
|
|
{
|
|
*ppObjectTypeList = LsapAllocateLsaHeap( pOutParam->Length );
|
|
fObjectTypeListAllocated = TRUE;
|
|
}
|
|
|
|
if ( *ppObjectTypeList == NULL )
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
pOutParam->Address = *ppObjectTypeList;
|
|
pOutParam->Data[1] = ObjectTypeIndex;
|
|
|
|
//
|
|
// the structure of each element is identical
|
|
// therefore just copy them all in one shot
|
|
//
|
|
|
|
RtlCopyMemory( *ppObjectTypeList,
|
|
pInObjectTypes->pObjectTypes,
|
|
pOutParam->Length );
|
|
(*ppObjectTypeList)[0].Flags = SE_ADT_OBJECT_ONLY;
|
|
break;
|
|
|
|
case APT_Time:
|
|
pOutParam->Type = SeAdtParmTypeTime;
|
|
FileTime.dwLowDateTime = (DWORD) pInParam->Data0;
|
|
FileTime.dwHighDateTime = (DWORD) pInParam->Data1;
|
|
*((FILETIME*) pOutParam->Data) = FileTime;
|
|
pOutParam->Length = sizeof(FILETIME);
|
|
break;
|
|
|
|
case APT_Int64:
|
|
pOutParam->Type = SeAdtParmTypeHexInt64;
|
|
Qword = pInParam->Data1;
|
|
Qword <<= 32;
|
|
Qword |= pInParam->Data0;
|
|
*((PULONGLONG) pOutParam->Data) = Qword;
|
|
pOutParam->Length = sizeof(ULONGLONG);
|
|
break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
//Cleanup:
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if ( fObjectTypeListAllocated )
|
|
{
|
|
LsapFreeLsaHeap( *ppObjectTypeList );
|
|
*ppObjectTypeList = NULL;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtFreeAuditContext(
|
|
AUDIT_HANDLE hAudit
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free resources allocated for the specified audit context
|
|
|
|
Arguments:
|
|
|
|
hAudit - handle to audit context to free
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PAUDIT_CONTEXT pAuditContext;
|
|
|
|
pAuditContext = AdtpContextPtrFromHandle( hAudit );
|
|
|
|
DsysAssertMsg(pAuditContext, "LsapAdtFreeAuditContext" );
|
|
|
|
DsysAssertMsg( LsapAdtIsValidAuditContext( hAudit ) == STATUS_SUCCESS,
|
|
"LsapAdtFreeAuditContext: audit context may be corrupt");
|
|
|
|
LsapFreeLsaHeap( pAuditContext );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtCheckAuditPrivilege()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if the rpc client has SeAuditPrivilege.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if privilege held
|
|
STATUS_PRIVILEGE_NOT_HELD if privilege not held
|
|
error codes returned by NtOpenThreadToken, NtQueryInformationToken
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_PRIVILEGE_NOT_HELD;
|
|
HANDLE hToken = NULL;
|
|
PRIVILEGE_SET PrivilegeSet = { 0 };
|
|
BOOLEAN fHasAuditPrivilege = FALSE;
|
|
BOOL fImpersonated = FALSE;
|
|
|
|
#if DBG
|
|
//
|
|
// make sure that we are not already impersonating
|
|
//
|
|
|
|
Status = NtOpenThreadToken( NtCurrentThread(), TOKEN_QUERY, TRUE, &hToken );
|
|
|
|
DsysAssertMsg( Status == STATUS_NO_TOKEN, "LsapAdtCheckAuditPrivilege" );
|
|
|
|
if ( NT_SUCCESS(Status) )
|
|
{
|
|
NtClose( hToken );
|
|
}
|
|
#endif
|
|
//
|
|
// impersonate rpc caller
|
|
//
|
|
|
|
Status = I_RpcMapWin32Status(RpcImpersonateClient( NULL ));
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
fImpersonated = TRUE;
|
|
Status = NtOpenThreadToken( NtCurrentThread(), TOKEN_QUERY,
|
|
TRUE, &hToken );
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
PrivilegeSet.PrivilegeCount = 1;
|
|
PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
|
|
PrivilegeSet.Privilege[0].Luid = AuditPrivilege;
|
|
PrivilegeSet.Privilege[0].Attributes = 0;
|
|
|
|
Status = NtPrivilegeCheck( hToken, &PrivilegeSet, &fHasAuditPrivilege );
|
|
|
|
if ( NT_SUCCESS(Status) && !fHasAuditPrivilege )
|
|
{
|
|
Status = STATUS_PRIVILEGE_NOT_HELD;
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
if ( hToken )
|
|
{
|
|
NtClose( hToken );
|
|
}
|
|
|
|
if ( fImpersonated )
|
|
{
|
|
NTSTATUS RevertStatus;
|
|
RevertStatus = I_RpcMapWin32Status(RpcRevertToSelf());
|
|
#if DBG
|
|
ASSERT(NT_SUCCESS(RevertStatus) && "Revert did not succeed.");
|
|
#endif
|
|
}
|
|
|
|
return Status;
|
|
}
|