1246 lines
31 KiB
C
1246 lines
31 KiB
C
//+-----------------------------------------------------------------------
|
||
//
|
||
// 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"
|
||
|
||
// ----------------------------------------------------------------------
|
||
//
|
||
// 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
|
||
LsapAdtMapAuditParams(
|
||
IN PAUDIT_PARAMS pAuditParams,
|
||
OUT PSE_ADT_PARAMETER_ARRAY pSeAuditParameters,
|
||
OUT PUNICODE_STRING pString,
|
||
OUT PSE_ADT_OBJECT_TYPE* pObjectTypeList
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapAdtFreeAuditContext(
|
||
AUDIT_HANDLE hAudit
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapAdtCheckAuditPrivilege( VOID );
|
||
|
||
// ----------------------------------------------------------------------
|
||
|
||
|
||
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 };
|
||
|
||
#define MAX_OBJECT_TYPES 32
|
||
|
||
SE_ADT_OBJECT_TYPE ObjectTypes[MAX_OBJECT_TYPES];
|
||
PSE_ADT_OBJECT_TYPE pObjectTypes = ObjectTypes;
|
||
POLICY_AUDIT_EVENT_TYPE CategoryId;
|
||
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;
|
||
}
|
||
|
||
//
|
||
// do the ugly math since the corresponding values of
|
||
// POLICY_AUDIT_EVENT_TYPE (ntlsa.h) and those defined
|
||
// in msaudite.h differ by 1
|
||
//
|
||
|
||
CategoryId = (POLICY_AUDIT_EVENT_TYPE) (pAuditContext->CategoryId - 1);
|
||
|
||
//
|
||
// check if auditing is enabled for that category
|
||
//
|
||
|
||
if (!LsapAdtIsAuditingEnabledForCategory( CategoryId, AuditEventType ))
|
||
{
|
||
Status = STATUS_AUDITING_DISABLED;
|
||
goto Cleanup;
|
||
}
|
||
|
||
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, 0 );
|
||
|
||
|
||
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;
|
||
}
|
||
|
||
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 ) &&
|
||
IsValidParameterCount( pAuditEventType->u.Legacy.ParameterCount ) )
|
||
{
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
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;
|
||
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.
|
||
//
|
||
|
||
case APT_String:
|
||
DsysAssertMsg( pInParam->Data0, "APT_String" );
|
||
|
||
RtlInitUnicodeString( pString, (PCWSTR) pInParam->Data0 );
|
||
pOutParam->Type = SeAdtParmTypeString;
|
||
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:
|
||
DsysAssertMsg( pInParam->Data0, "APT_Sid" );
|
||
|
||
pOutParam->Type = SeAdtParmTypeSid;
|
||
pOutParam->Address = (PVOID) pInParam->Data0;
|
||
pOutParam->Length = RtlLengthSid( (PSID) pInParam->Data0 );
|
||
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_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" );
|
||
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
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 )
|
||
{
|
||
Status = I_RpcMapWin32Status(RpcRevertToSelf());
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|