You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2126 lines
68 KiB
2126 lines
68 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
adtmarshal.c
|
|
|
|
Abstract:
|
|
|
|
Functions (de)marshalling of audit parameters
|
|
|
|
Author:
|
|
|
|
16-August-2000 kumarp
|
|
|
|
--*/
|
|
|
|
#include <lsapch2.h>
|
|
#include "adtp.h"
|
|
#include "adtutil.h"
|
|
#include "adtdebug.h"
|
|
|
|
extern HANDLE LsapAdtLogHandle;
|
|
extern ULONG LsapAdtSuccessCount;
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtDemarshallAuditInfo(
|
|
IN PSE_ADT_PARAMETER_ARRAY AuditParameters
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will walk down a marshalled audit parameter
|
|
array and unpack it so that its information may be passed
|
|
into the event logging service.
|
|
|
|
Three parallel data structures are maintained:
|
|
|
|
StringArray - Array of Unicode string structures. This array
|
|
is used primarily as temporary storage for returned string
|
|
structures.
|
|
|
|
StringPointerArray - Array of pointers to Unicode string structures.
|
|
|
|
FreeWhenDone - Array of booleans describing how to dispose of each
|
|
of the strings pointed to by the StringPointerArray.
|
|
|
|
|
|
Note that entries in the StringPointerArray are contiguous, but that
|
|
there may be gaps in the StringArray structure. For each entry in the
|
|
StringPointerArray there will be a corresponding entry in the FreeWhenDone
|
|
array. If the entry for a particular string is TRUE, the storage for
|
|
the string buffer will be released to the process heap.
|
|
|
|
|
|
|
|
StringArray
|
|
Other strings
|
|
+----------------+
|
|
| |<-----------+ +----------------+
|
|
| | | | |<-------------------+
|
|
+----------------+ | | | |
|
|
| UNUSED | | +----------------+ |
|
|
| | | |
|
|
+----------------+ | |
|
|
| |<------+ | +----------------+ |
|
|
| | | | | |<-----------+ |
|
|
+----------------+ | | | | | |
|
|
| UNUSED | | | +----------------+ | |
|
|
| | | | | |
|
|
+----------------+ | | | |
|
|
| |<--+ | | | |
|
|
| | | | | | |
|
|
+----------------+ | | | | |
|
|
| | | | | | |
|
|
| | | | | StringPointerArray | |
|
|
.... | | | | |
|
|
| | | +----------------+ | |
|
|
| | +-----| | | |
|
|
| | +----------------+ | |
|
|
| | | |---------+ |
|
|
| | +----------------+ |
|
|
| +----------| | |
|
|
| +----------------+ |
|
|
| | |-----------------+
|
|
| +----------------+
|
|
+--------------| |
|
|
+----------------+
|
|
| |
|
|
+----------------+
|
|
| |
|
|
+----------------+
|
|
| |
|
|
....
|
|
|
|
|
|
Arguments:
|
|
|
|
AuditParameters - Receives a pointer to an audit
|
|
parameters array in self-relative form.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG ParameterCount;
|
|
USHORT i;
|
|
PUNICODE_STRING StringPointerArray[SE_MAX_AUDIT_PARAM_STRINGS];
|
|
UNICODE_STRING NewObjectTypeName;
|
|
ULONG NewObjectTypeStringIndex = 0;
|
|
BOOLEAN FreeWhenDone[SE_MAX_AUDIT_PARAM_STRINGS];
|
|
UNICODE_STRING StringArray[SE_MAX_AUDIT_PARAM_STRINGS];
|
|
USHORT StringIndexArray[SE_MAX_AUDIT_PARAM_STRINGS];
|
|
USHORT StringIndex = 0;
|
|
UNICODE_STRING DashString;
|
|
BOOLEAN FreeDash;
|
|
NTSTATUS Status;
|
|
PUNICODE_STRING SourceModule;
|
|
PSID UserSid;
|
|
ULONG AuditId;
|
|
GUID NullGuid = { 0 };
|
|
|
|
AuditId = AuditParameters->AuditId;
|
|
|
|
//
|
|
// In w2k several events were introduced as explicit sucess/failure
|
|
// cases. In whistler, we corrected this by folding each these event
|
|
// pairs into a single event. We have retained the old failure event
|
|
// schema so that anybody viewing w2k events from a whistler
|
|
// machine can view them correctly.
|
|
//
|
|
// However, assert that we are not generating these events.
|
|
//
|
|
ASSERT((AuditId != SE_AUDITID_ADD_SID_HISTORY_FAILURE) &&
|
|
(AuditId != SE_AUDITID_AS_TICKET_FAILURE) &&
|
|
(AuditId != SE_AUDITID_ACCOUNT_LOGON_FAILURE) &&
|
|
(AuditId != SE_AUDITID_ACCOUNT_NOT_MAPPED) &&
|
|
(AuditId != SE_AUDITID_TGS_TICKET_FAILURE));
|
|
|
|
//
|
|
// Initialization.
|
|
//
|
|
|
|
RtlZeroMemory( StringPointerArray, sizeof(StringPointerArray) );
|
|
RtlZeroMemory( StringIndexArray, sizeof(StringIndexArray) );
|
|
RtlZeroMemory( StringArray, sizeof(StringArray) );
|
|
RtlZeroMemory( FreeWhenDone, sizeof(FreeWhenDone) );
|
|
|
|
RtlInitUnicodeString( &NewObjectTypeName, NULL );
|
|
|
|
Status = LsapAdtBuildDashString(
|
|
&DashString,
|
|
&FreeDash
|
|
);
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
ParameterCount = AuditParameters->ParameterCount;
|
|
|
|
//
|
|
// Parameter 0 will always be the user SID. Convert the
|
|
// offset to the SID into a pointer.
|
|
//
|
|
|
|
ASSERT( AuditParameters->Parameters[0].Type == SeAdtParmTypeSid );
|
|
|
|
|
|
|
|
UserSid = (PSID)AuditParameters->Parameters[0].Address;
|
|
|
|
|
|
|
|
//
|
|
// Parameter 1 will always be the Source Module (or Subsystem Name).
|
|
// Unpack this now.
|
|
//
|
|
|
|
ASSERT( AuditParameters->Parameters[1].Type == SeAdtParmTypeString );
|
|
|
|
|
|
|
|
SourceModule = (PUNICODE_STRING)AuditParameters->Parameters[1].Address;
|
|
|
|
|
|
for (i=2; i<ParameterCount; i++) {
|
|
StringIndexArray[i] = StringIndex;
|
|
|
|
switch ( AuditParameters->Parameters[i].Type ) {
|
|
//
|
|
// guard against somebody adding a new param type and not
|
|
// adding appropriate code here.
|
|
//
|
|
default:
|
|
ASSERT( FALSE && L"LsapAdtDemarshallAuditInfo: unknown param type");
|
|
break;
|
|
|
|
case SeAdtParmTypeNone:
|
|
{
|
|
StringPointerArray[StringIndex] = &DashString;
|
|
|
|
FreeWhenDone[StringIndex] = FALSE;
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeString:
|
|
{
|
|
StringPointerArray[StringIndex] =
|
|
(PUNICODE_STRING)AuditParameters->Parameters[i].Address;
|
|
|
|
FreeWhenDone[StringIndex] = FALSE;
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeFileSpec:
|
|
{
|
|
//
|
|
// Same as a string, except we must attempt to replace
|
|
// device information with a drive letter.
|
|
//
|
|
|
|
StringPointerArray[StringIndex] =
|
|
(PUNICODE_STRING)AuditParameters->Parameters[i].Address;
|
|
|
|
|
|
//
|
|
// This may not do anything, in which case just audit what
|
|
// we have.
|
|
//
|
|
|
|
LsapAdtSubstituteDriveLetter( StringPointerArray[StringIndex] );
|
|
|
|
FreeWhenDone[StringIndex] = FALSE;
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeUlong:
|
|
{
|
|
ULONG Data;
|
|
|
|
Data = (ULONG) AuditParameters->Parameters[i].Data[0];
|
|
|
|
Status = LsapAdtBuildUlongString(
|
|
Data,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
|
|
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeHexUlong:
|
|
{
|
|
ULONG Data;
|
|
|
|
Data = (ULONG) AuditParameters->Parameters[i].Data[0];
|
|
|
|
Status = LsapAdtBuildHexUlongString(
|
|
Data,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
|
|
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeSid:
|
|
{
|
|
PSID Sid;
|
|
|
|
Sid = (PSID)AuditParameters->Parameters[i].Address;
|
|
|
|
Status = LsapAdtBuildSidString(
|
|
Sid,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
case SeAdtParmTypeLuid:
|
|
{
|
|
PLUID Luid;
|
|
|
|
Luid = (PLUID)(&AuditParameters->Parameters[i].Data[0]);
|
|
|
|
Status = LsapAdtBuildLuidString(
|
|
Luid,
|
|
&StringArray[ StringIndex ],
|
|
&FreeWhenDone[ StringIndex ]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
StringIndex++;
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Finished, break out to surrounding loop.
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
case SeAdtParmTypeLogonId:
|
|
{
|
|
PLUID LogonId;
|
|
ULONG j;
|
|
|
|
LogonId = (PLUID)(&AuditParameters->Parameters[i].Data[0]);
|
|
|
|
Status = LsapAdtBuildLogonIdStrings(
|
|
LogonId,
|
|
&StringArray [ StringIndex ],
|
|
&FreeWhenDone[ StringIndex ],
|
|
&StringArray [ StringIndex + 1 ],
|
|
&FreeWhenDone[ StringIndex + 1 ],
|
|
&StringArray [ StringIndex + 2 ],
|
|
&FreeWhenDone[ StringIndex + 2 ]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
for (j=0; j<3; j++) {
|
|
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
StringIndex++;
|
|
}
|
|
|
|
//
|
|
// Finished, break out to surrounding loop.
|
|
//
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
break;
|
|
}
|
|
case SeAdtParmTypeNoLogonId:
|
|
{
|
|
ULONG j;
|
|
//
|
|
// Create three "-" strings.
|
|
//
|
|
|
|
for (j=0; j<3; j++) {
|
|
|
|
StringPointerArray[ StringIndex ] = &DashString;
|
|
FreeWhenDone[ StringIndex ] = FALSE;
|
|
StringIndex++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeAccessMask:
|
|
{
|
|
PUNICODE_STRING ObjectTypeName;
|
|
ULONG ObjectTypeNameIndex;
|
|
ACCESS_MASK Accesses;
|
|
|
|
ObjectTypeNameIndex = (ULONG) AuditParameters->Parameters[i].Data[1];
|
|
|
|
//
|
|
// the parameter that denotes the object's type must
|
|
// have been specified earlier and must be a string.
|
|
//
|
|
|
|
if ((ObjectTypeNameIndex >= i) ||
|
|
(AuditParameters->Parameters[ObjectTypeNameIndex].Type !=
|
|
SeAdtParmTypeString)) {
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ObjectTypeName = AuditParameters->Parameters[ObjectTypeNameIndex].Address;
|
|
Accesses = (ACCESS_MASK) AuditParameters->Parameters[i].Data[0];
|
|
|
|
//
|
|
// We can determine the index to the ObjectTypeName
|
|
// parameter since it was stored away in the Data[1]
|
|
// field of this parameter.
|
|
//
|
|
|
|
Status = LsapAdtBuildAccessesString(
|
|
SourceModule,
|
|
ObjectTypeName,
|
|
Accesses,
|
|
TRUE,
|
|
&StringArray [ StringIndex ],
|
|
&FreeWhenDone[ StringIndex ]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
StringPointerArray[ StringIndex ] = &StringArray[ StringIndex ];
|
|
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypePrivs:
|
|
{
|
|
|
|
PPRIVILEGE_SET Privileges = (PPRIVILEGE_SET)AuditParameters->Parameters[i].Address;
|
|
|
|
Status = LsapBuildPrivilegeAuditString(
|
|
Privileges,
|
|
&StringArray [ StringIndex ],
|
|
&FreeWhenDone[ StringIndex ]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
StringPointerArray[ StringIndex ] = &StringArray[ StringIndex ];
|
|
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeTime:
|
|
{
|
|
PLARGE_INTEGER pTime;
|
|
|
|
pTime = (PLARGE_INTEGER) &AuditParameters->Parameters[i].Data[0];
|
|
|
|
//
|
|
// First build a date string.
|
|
//
|
|
|
|
Status = LsapAdtBuildDateString(
|
|
pTime,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
|
|
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
//
|
|
// Now build a time string.
|
|
//
|
|
|
|
Status = LsapAdtBuildTimeString(
|
|
pTime,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
|
|
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeDuration:
|
|
{
|
|
PLARGE_INTEGER pDuration;
|
|
|
|
pDuration = (PLARGE_INTEGER) &AuditParameters->Parameters[i].Data[0];
|
|
|
|
Status = LsapAdtBuildDurationString(
|
|
pDuration,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status ))
|
|
{
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
}
|
|
else
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeObjectTypes:
|
|
{
|
|
PUNICODE_STRING ObjectTypeName;
|
|
ULONG ObjectTypeNameIndex;
|
|
PSE_ADT_OBJECT_TYPE ObjectTypeList;
|
|
ULONG ObjectTypeCount;
|
|
ULONG j;
|
|
|
|
ObjectTypeNameIndex = (ULONG) AuditParameters->Parameters[i].Data[1];
|
|
//
|
|
// the parameter that denotes the object's type must
|
|
// have been specified earlier and must be a string.
|
|
//
|
|
|
|
if ((ObjectTypeNameIndex >= i) ||
|
|
(AuditParameters->Parameters[ObjectTypeNameIndex].Type !=
|
|
SeAdtParmTypeString)) {
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
NewObjectTypeStringIndex = StringIndexArray[ObjectTypeNameIndex];
|
|
ObjectTypeName = AuditParameters->Parameters[ObjectTypeNameIndex].Address;
|
|
ObjectTypeList = AuditParameters->Parameters[i].Address;
|
|
ObjectTypeCount = AuditParameters->Parameters[i].Length / sizeof(SE_ADT_OBJECT_TYPE);
|
|
|
|
//
|
|
// Will Fill in 10 entries.
|
|
//
|
|
|
|
(VOID) LsapAdtBuildObjectTypeStrings(
|
|
SourceModule,
|
|
ObjectTypeName,
|
|
ObjectTypeList,
|
|
ObjectTypeCount,
|
|
&StringArray [ StringIndex ],
|
|
&FreeWhenDone[ StringIndex ],
|
|
&NewObjectTypeName
|
|
);
|
|
|
|
for (j=0; j < LSAP_ADT_OBJECT_TYPE_STRINGS; j++) {
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
StringIndex++;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// &StringArray [ StringIndexArray[ObjectTypeNameIndex]],
|
|
// &FreeWhenDone[ StringIndexArray[ObjectTypeNameIndex]],
|
|
|
|
//
|
|
// Finished, break out to surrounding loop.
|
|
//
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypePtr:
|
|
{
|
|
PVOID Data;
|
|
|
|
Data = (PVOID) AuditParameters->Parameters[i].Data[0];
|
|
|
|
Status = LsapAdtBuildPtrString(
|
|
Data,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
|
|
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeGuid:
|
|
{
|
|
LPGUID pGuid;
|
|
|
|
pGuid = (LPGUID)AuditParameters->Parameters[i].Address;
|
|
|
|
//
|
|
// check for NULL guid
|
|
//
|
|
|
|
if ( pGuid && memcmp( pGuid, &NullGuid, sizeof(GUID)))
|
|
{
|
|
//
|
|
// generate a string GUID only for non-NULL guids
|
|
//
|
|
|
|
Status = LsapAdtBuildGuidString(
|
|
pGuid,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
|
|
} else {
|
|
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// for NULL guids, display a '-' string
|
|
//
|
|
|
|
StringPointerArray[StringIndex] = &DashString;
|
|
FreeWhenDone[StringIndex] = FALSE;
|
|
}
|
|
|
|
StringIndex++;
|
|
break;
|
|
}
|
|
case SeAdtParmTypeHexInt64:
|
|
{
|
|
PULONGLONG pData;
|
|
|
|
pData = (PULONGLONG) AuditParameters->Parameters[i].Data;
|
|
|
|
Status = LsapAdtBuildHexInt64String(
|
|
pData,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
}
|
|
else
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeStringList:
|
|
{
|
|
PLSA_ADT_STRING_LIST pList = (PLSA_ADT_STRING_LIST)AuditParameters->Parameters[i].Address;
|
|
|
|
Status = LsapAdtBuildStringListString(
|
|
pList,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
}
|
|
else
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeSidList:
|
|
{
|
|
PLSA_ADT_SID_LIST pList = (PLSA_ADT_SID_LIST)AuditParameters->Parameters[i].Address;
|
|
|
|
Status = LsapAdtBuildSidListString(
|
|
pList,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
}
|
|
else
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeUserAccountControl:
|
|
{
|
|
ULONG j;
|
|
|
|
Status = LsapAdtBuildUserAccountControlString(
|
|
(ULONG)(AuditParameters->Parameters[i].Data[0]), // old uac value
|
|
(ULONG)(AuditParameters->Parameters[i].Data[1]), // new uac value
|
|
&StringArray [ StringIndex ],
|
|
&FreeWhenDone[ StringIndex ],
|
|
&StringArray [ StringIndex + 1 ],
|
|
&FreeWhenDone[ StringIndex + 1 ],
|
|
&StringArray [ StringIndex + 2 ],
|
|
&FreeWhenDone[ StringIndex + 2 ]
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
for (j=0;j < 3;j++)
|
|
{
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
StringIndex++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeNoUac:
|
|
{
|
|
ULONG j;
|
|
|
|
for (j=0;j < 3;j++)
|
|
{
|
|
StringPointerArray[ StringIndex ] = &DashString;
|
|
FreeWhenDone[ StringIndex ] = FALSE;
|
|
StringIndex++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeMessage:
|
|
{
|
|
ULONG MessageId = (ULONG)AuditParameters->Parameters[i].Data[0];
|
|
|
|
Status = LsapAdtBuildMessageString(
|
|
MessageId,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
}
|
|
else
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeDateTime:
|
|
{
|
|
PLARGE_INTEGER pTime;
|
|
|
|
pTime = (PLARGE_INTEGER)&AuditParameters->Parameters[i].Data[0];
|
|
|
|
Status = LsapAdtBuildDateTimeString(
|
|
pTime,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex]
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
}
|
|
else
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringIndex++;
|
|
|
|
break;
|
|
}
|
|
|
|
case SeAdtParmTypeSockAddr:
|
|
{
|
|
PSOCKADDR pSockAddr;
|
|
|
|
pSockAddr = (PSOCKADDR) AuditParameters->Parameters[i].Address;
|
|
|
|
Status = LsapAdtBuildSockAddrString(
|
|
pSockAddr,
|
|
&StringArray[StringIndex],
|
|
&FreeWhenDone[StringIndex],
|
|
&StringArray[StringIndex+1],
|
|
&FreeWhenDone[StringIndex+1]
|
|
);
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
StringIndex++;
|
|
|
|
StringPointerArray[StringIndex] = &StringArray[StringIndex];
|
|
StringIndex++;
|
|
}
|
|
else
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the generic object type name has been converted to something
|
|
// specific to this audit,
|
|
// substitute it now.
|
|
//
|
|
|
|
if ( NewObjectTypeName.Length != 0 ) {
|
|
|
|
//
|
|
// Free the previous object type name.
|
|
//
|
|
if ( FreeWhenDone[NewObjectTypeStringIndex] ) {
|
|
LsapFreeLsaHeap( StringPointerArray[NewObjectTypeStringIndex]->Buffer );
|
|
}
|
|
|
|
//
|
|
// Save the new object type name.
|
|
//
|
|
|
|
FreeWhenDone[NewObjectTypeStringIndex] = TRUE;
|
|
StringPointerArray[NewObjectTypeStringIndex] = &NewObjectTypeName;
|
|
|
|
}
|
|
|
|
#if DBG
|
|
|
|
AdtDebugOut((DEB_AUDIT_STRS, "Cat: %d, Event: %d, %s, UserSid: %p\n",
|
|
AuditParameters->CategoryId, AuditId,
|
|
AuditParameters->Type == EVENTLOG_AUDIT_SUCCESS ? "S" : "F",
|
|
UserSid));
|
|
|
|
//
|
|
// do some sanity check on the strings that we pass to ElfReportEventW.
|
|
// If we dont do it here, it will be caught by ElfReportEventW and
|
|
// it will involve more steps in debugger to determine the string
|
|
// at fault. Checking it here saves us that trouble.
|
|
//
|
|
|
|
for (i=0; i<StringIndex; i++) {
|
|
|
|
PUNICODE_STRING TempString;
|
|
|
|
TempString = StringPointerArray[i];
|
|
|
|
if ( !TempString )
|
|
{
|
|
DbgPrint( "LsapAdtDemarshallAuditInfo: string %d is NULL\n", i );
|
|
}
|
|
else if (!LsapIsValidUnicodeString( TempString ))
|
|
{
|
|
DbgPrint( "LsapAdtDemarshallAuditInfo: invalid string: %d @ %p ('%wZ' [%d / %d])\n",
|
|
i, TempString,
|
|
TempString, TempString->Length, TempString->MaximumLength);
|
|
ASSERT( L"LsapAdtDemarshallAuditInfo: invalid string" && FALSE );
|
|
}
|
|
else
|
|
{
|
|
AdtDebugOut((DEB_AUDIT_STRS, "%02d] @ %p ([%d / %d] '%wZ')\n",
|
|
i, TempString,
|
|
TempString->Length, TempString->MaximumLength,
|
|
TempString));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Probably have to do this from somewhere else eventually, but for now
|
|
// do it from here.
|
|
//
|
|
|
|
Status = ElfReportEventW (
|
|
LsapAdtLogHandle,
|
|
AuditParameters->Type,
|
|
(USHORT)AuditParameters->CategoryId,
|
|
AuditId,
|
|
UserSid,
|
|
StringIndex,
|
|
0,
|
|
StringPointerArray,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Increment the number of audits successfully
|
|
// written to the log.
|
|
//
|
|
|
|
++LsapAdtSuccessCount;
|
|
}
|
|
|
|
//
|
|
// If we are shutting down and we got an expected error back from the
|
|
// eventlog, don't worry about it. This prevents bugchecking from an
|
|
// audit failure while shutting down.
|
|
//
|
|
|
|
if ((Status == RPC_NT_UNKNOWN_IF) || (Status == STATUS_UNSUCCESSFUL))
|
|
{
|
|
#if DBG
|
|
//
|
|
// During shutdown, sometimes eventlog stops before LSA has a chance
|
|
// to set LsapState.SystemShutdownPending. This causes the assert below.
|
|
// In debug builds, sleep for some time to see if this state
|
|
// variable gets set. This reduces the chance of the assert
|
|
// showing up during shutdown.
|
|
//
|
|
|
|
{
|
|
ULONG RetryCount;
|
|
|
|
RetryCount = 0;
|
|
|
|
//
|
|
// wait upto 60 sec to see if we are shutting down.
|
|
//
|
|
|
|
while ( !LsapState.SystemShutdownPending && (RetryCount < 60))
|
|
{
|
|
Sleep(1000);
|
|
RetryCount++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( LsapState.SystemShutdownPending )
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if ( !NT_SUCCESS(Status) )
|
|
{
|
|
#if DBG
|
|
//
|
|
// we do not assert if Status is one of the noisy codes
|
|
// see the macro LsapAdtNeedToAssert for a complete list of codes.
|
|
//
|
|
|
|
if (LsapAdtNeedToAssert( Status ))
|
|
{
|
|
DbgPrint( "LsapAdtDemarshallAuditInfo: failed: %x\n", Status );
|
|
DsysAssertMsg( FALSE, "LsapAdtDemarshallAuditInfo: failed" );
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If we couldn't log the audit and we are trying to write
|
|
// an 'audit failed' audit, report success to avoid an infinite loop.
|
|
//
|
|
|
|
if ( AuditParameters->AuditId == SE_AUDITID_UNABLE_TO_LOG_EVENTS )
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
LsapAuditFailed( Status );
|
|
}
|
|
}
|
|
|
|
for (i=0; i<StringIndex; i++) {
|
|
|
|
if (FreeWhenDone[i]) {
|
|
LsapFreeLsaHeap( StringPointerArray[i]->Buffer );
|
|
}
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
LsapAdtNormalizeAuditInfo(
|
|
IN PSE_ADT_PARAMETER_ARRAY AuditParameters
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will walk down a marshalled audit parameter
|
|
array and turn it into an Absolute format data structure.
|
|
|
|
|
|
Arguments:
|
|
|
|
AuditParameters - Receives a pointer to an audit
|
|
parameters array in self-relative form.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ParameterCount;
|
|
ULONG i;
|
|
PUNICODE_STRING Unicode;
|
|
|
|
|
|
if ( !(AuditParameters->Flags & SE_ADT_PARAMETERS_SELF_RELATIVE)) {
|
|
|
|
return;
|
|
}
|
|
|
|
ParameterCount = AuditParameters->ParameterCount;
|
|
|
|
for (i=0; i<ParameterCount; i++) {
|
|
|
|
switch ( AuditParameters->Parameters[i].Type ) {
|
|
//
|
|
// guard against somebody adding a new param type and not
|
|
// adding appropriate code here.
|
|
//
|
|
default:
|
|
ASSERT( FALSE && L"LsapAdtNormalizeAuditInfo: unknown param type");
|
|
break;
|
|
|
|
case SeAdtParmTypeNone:
|
|
case SeAdtParmTypeUlong:
|
|
case SeAdtParmTypeHexUlong:
|
|
case SeAdtParmTypeHexInt64:
|
|
case SeAdtParmTypeTime:
|
|
case SeAdtParmTypeDuration:
|
|
case SeAdtParmTypeLogonId:
|
|
case SeAdtParmTypeNoLogonId:
|
|
case SeAdtParmTypeAccessMask:
|
|
case SeAdtParmTypePtr:
|
|
case SeAdtParmTypeLuid:
|
|
case SeAdtParmTypeUserAccountControl:
|
|
case SeAdtParmTypeNoUac:
|
|
case SeAdtParmTypeMessage:
|
|
case SeAdtParmTypeDateTime:
|
|
{
|
|
|
|
break;
|
|
}
|
|
case SeAdtParmTypeGuid:
|
|
case SeAdtParmTypeSid:
|
|
case SeAdtParmTypePrivs:
|
|
case SeAdtParmTypeObjectTypes:
|
|
case SeAdtParmTypeString:
|
|
case SeAdtParmTypeFileSpec:
|
|
case SeAdtParmTypeSockAddr:
|
|
{
|
|
PUCHAR Fixup;
|
|
|
|
Fixup = ((PUCHAR) AuditParameters ) +
|
|
(ULONG_PTR) AuditParameters->Parameters[i].Address ;
|
|
|
|
AuditParameters->Parameters[i].Address = (PVOID) Fixup;
|
|
|
|
if ( (AuditParameters->Parameters[i].Type == SeAdtParmTypeString) ||
|
|
(AuditParameters->Parameters[i].Type == SeAdtParmTypeFileSpec ) )
|
|
{
|
|
//
|
|
// For the string types, also fix up the buffer pointer
|
|
// in the UNICODE_STRING
|
|
//
|
|
|
|
Unicode = (PUNICODE_STRING) Fixup ;
|
|
Unicode->Buffer = (PWSTR)((PCHAR)Unicode->Buffer + (ULONG_PTR)AuditParameters);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SeAdtParmTypeStringList:
|
|
{
|
|
PCHAR pFixup;
|
|
ULONG e;
|
|
ULONG_PTR Delta = (ULONG_PTR)AuditParameters;
|
|
PLSA_ADT_STRING_LIST pList;
|
|
PLSA_ADT_STRING_LIST_ENTRY pEntry;
|
|
|
|
pFixup = (PCHAR)AuditParameters->Parameters[i].Address;
|
|
pFixup += Delta;
|
|
AuditParameters->Parameters[i].Address = (PVOID)pFixup;
|
|
|
|
pList = (PLSA_ADT_STRING_LIST)AuditParameters->Parameters[i].Address;
|
|
|
|
if (pList->cStrings)
|
|
{
|
|
pFixup = (PCHAR)pList->Strings;
|
|
pFixup += Delta;
|
|
pList->Strings = (PLSA_ADT_STRING_LIST_ENTRY)pFixup;
|
|
|
|
for (
|
|
e = 0, pEntry = pList->Strings;
|
|
e < pList->cStrings;
|
|
e++, pEntry++)
|
|
{
|
|
pFixup = (PCHAR)pEntry->String.Buffer;
|
|
pFixup += Delta;
|
|
pEntry->String.Buffer = (PWSTR)pFixup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pList->Strings = 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SeAdtParmTypeSidList:
|
|
{
|
|
PCHAR pFixup;
|
|
ULONG e;
|
|
ULONG_PTR Delta = (ULONG_PTR)AuditParameters;
|
|
PLSA_ADT_SID_LIST pList;
|
|
PLSA_ADT_SID_LIST_ENTRY pEntry;
|
|
|
|
pFixup = (PCHAR)AuditParameters->Parameters[i].Address;
|
|
pFixup += Delta;
|
|
AuditParameters->Parameters[i].Address = (PVOID)pFixup;
|
|
|
|
pList = (PLSA_ADT_SID_LIST)AuditParameters->Parameters[i].Address;
|
|
|
|
if (pList->cSids)
|
|
{
|
|
pFixup = (PCHAR)pList->Sids;
|
|
pFixup += Delta;
|
|
pList->Sids = (PLSA_ADT_SID_LIST_ENTRY)pFixup;
|
|
|
|
for (
|
|
e = 0, pEntry = pList->Sids;
|
|
e < pList->cSids;
|
|
e++, pEntry++)
|
|
{
|
|
pFixup = (PCHAR)pEntry->Sid;
|
|
pFixup += Delta;
|
|
pEntry->Sid = (PSID)pFixup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pList->Sids = 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtMarshallAuditRecord(
|
|
IN PSE_ADT_PARAMETER_ARRAY AuditParameters,
|
|
OUT PSE_ADT_PARAMETER_ARRAY *MarshalledAuditParameters
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will take an AuditParamters structure and create
|
|
a new AuditParameters structure that is suitable for placing
|
|
to LSA queue. It will be in self-relative form and allocated as
|
|
a single chunk of memory.
|
|
|
|
Arguments:
|
|
|
|
|
|
AuditParameters - A filled in set of AuditParameters to be marshalled.
|
|
|
|
MarshalledAuditParameters - Returns a pointer to a block of heap memory
|
|
containing the passed AuditParameters in self-relative form suitable
|
|
for passing to LSA.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
ULONG TotalSize = sizeof( SE_ADT_PARAMETER_ARRAY );
|
|
PUNICODE_STRING TargetString;
|
|
PCHAR Base;
|
|
ULONG BaseIncr;
|
|
ULONG Size;
|
|
PSE_ADT_PARAMETER_ARRAY_ENTRY pInParam, pOutParam;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
//
|
|
// Calculate the total size required for the passed AuditParameters
|
|
// block. This calculation will probably be an overestimate of the
|
|
// amount of space needed, because data smaller that 2 dwords will
|
|
// be stored directly in the parameters structure, but their length
|
|
// will be counted here anyway. The overestimate can't be more than
|
|
// 24 dwords, and will never even approach that amount, so it isn't
|
|
// worth the time it would take to avoid it.
|
|
//
|
|
|
|
for (i=0; i<AuditParameters->ParameterCount; i++) {
|
|
Size = AuditParameters->Parameters[i].Length;
|
|
TotalSize += PtrAlignSize( Size );
|
|
}
|
|
|
|
//
|
|
// Allocate a big enough block of memory to hold everything.
|
|
// If it fails, quietly abort, since there isn't much else we
|
|
// can do.
|
|
//
|
|
|
|
*MarshalledAuditParameters = LsapAllocateLsaHeap( TotalSize );
|
|
|
|
if (*MarshalledAuditParameters == NULL) {
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Cleanup;
|
|
}
|
|
|
|
RtlCopyMemory (
|
|
*MarshalledAuditParameters,
|
|
AuditParameters,
|
|
sizeof( SE_ADT_PARAMETER_ARRAY )
|
|
);
|
|
|
|
(*MarshalledAuditParameters)->Length = TotalSize;
|
|
(*MarshalledAuditParameters)->Flags = SE_ADT_PARAMETERS_SELF_RELATIVE;
|
|
|
|
pInParam = &AuditParameters->Parameters[0];
|
|
pOutParam = &((*MarshalledAuditParameters)->Parameters[0]);
|
|
|
|
//
|
|
// Start walking down the list of parameters and marshall them
|
|
// into the target buffer.
|
|
//
|
|
|
|
Base = (PCHAR) ((PCHAR)(*MarshalledAuditParameters) + sizeof( SE_ADT_PARAMETER_ARRAY ));
|
|
|
|
for (i=0; i<AuditParameters->ParameterCount; i++, pInParam++, pOutParam++) {
|
|
|
|
|
|
switch (pInParam->Type) {
|
|
//
|
|
// guard against somebody adding a new param type and not
|
|
// adding appropriate code here.
|
|
//
|
|
default:
|
|
ASSERT( FALSE && L"LsapAdtMarshallAuditRecord: unknown param type");
|
|
break;
|
|
|
|
case SeAdtParmTypeNone:
|
|
case SeAdtParmTypeUlong:
|
|
case SeAdtParmTypeHexUlong:
|
|
case SeAdtParmTypeHexInt64:
|
|
case SeAdtParmTypeLogonId:
|
|
case SeAdtParmTypeLuid:
|
|
case SeAdtParmTypeNoLogonId:
|
|
case SeAdtParmTypeAccessMask:
|
|
case SeAdtParmTypePtr:
|
|
case SeAdtParmTypeTime:
|
|
case SeAdtParmTypeDuration:
|
|
case SeAdtParmTypeUserAccountControl:
|
|
case SeAdtParmTypeNoUac:
|
|
case SeAdtParmTypeMessage:
|
|
case SeAdtParmTypeDateTime:
|
|
{
|
|
//
|
|
// Nothing to do for this
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
case SeAdtParmTypeFileSpec:
|
|
case SeAdtParmTypeString:
|
|
{
|
|
PUNICODE_STRING SourceString;
|
|
|
|
//
|
|
// We must copy the body of the unicode string
|
|
// and then copy the body of the string. Pointers
|
|
// must be turned into offsets.
|
|
|
|
TargetString = (PUNICODE_STRING)Base;
|
|
|
|
SourceString = pInParam->Address;
|
|
|
|
*TargetString = *SourceString;
|
|
|
|
//
|
|
// Reset the data pointer in the output parameters to
|
|
// 'point' to the new string structure.
|
|
//
|
|
|
|
pOutParam->Address = Base - (ULONG_PTR)(*MarshalledAuditParameters);
|
|
|
|
Base += sizeof( UNICODE_STRING );
|
|
|
|
RtlCopyMemory( Base, SourceString->Buffer, SourceString->Length );
|
|
|
|
//
|
|
// Make the string buffer in the target string point to where we
|
|
// just copied the data.
|
|
//
|
|
|
|
TargetString->Buffer = (PWSTR)(Base - (ULONG_PTR)(*MarshalledAuditParameters));
|
|
|
|
BaseIncr = PtrAlignSize(SourceString->Length);
|
|
|
|
Base += BaseIncr;
|
|
|
|
ASSERT( (ULONG_PTR)Base <= (ULONG_PTR)(*MarshalledAuditParameters) + TotalSize );
|
|
|
|
break;
|
|
}
|
|
|
|
case SeAdtParmTypeGuid:
|
|
case SeAdtParmTypeSid:
|
|
case SeAdtParmTypePrivs:
|
|
case SeAdtParmTypeObjectTypes:
|
|
case SeAdtParmTypeSockAddr:
|
|
{
|
|
#if DBG
|
|
switch (pInParam->Type)
|
|
{
|
|
case SeAdtParmTypeSid:
|
|
DsysAssertMsg( pInParam->Length >= RtlLengthSid(pInParam->Address),
|
|
"LsapAdtMarshallAuditRecord" );
|
|
if (!RtlValidSid((PSID) pInParam->Address))
|
|
{
|
|
Status = STATUS_INVALID_SID;
|
|
goto Cleanup;
|
|
}
|
|
break;
|
|
|
|
case SeAdtParmTypePrivs:
|
|
DsysAssertMsg( pInParam->Length >= LsapPrivilegeSetSize( (PPRIVILEGE_SET) pInParam->Address ),
|
|
"LsapAdtMarshallAuditRecord" );
|
|
if (!IsValidPrivilegeCount(((PPRIVILEGE_SET) pInParam->Address)->PrivilegeCount))
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
break;
|
|
|
|
case SeAdtParmTypeGuid:
|
|
DsysAssertMsg( pInParam->Length == sizeof(GUID),
|
|
"LsapAdtMarshallAuditRecord" );
|
|
break;
|
|
|
|
case SeAdtParmTypeSockAddr:
|
|
DsysAssertMsg((pInParam->Length == sizeof(SOCKADDR_IN)) ||
|
|
(pInParam->Length == sizeof(SOCKADDR_IN6)) ||
|
|
(pInParam->Length == sizeof(SOCKADDR)),
|
|
"LsapAdtMarshallAuditRecord" );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// Copy the data into the output buffer
|
|
//
|
|
|
|
RtlCopyMemory( Base, pInParam->Address, pInParam->Length );
|
|
|
|
//
|
|
// Reset the 'address' of the data to be its offset in the
|
|
// buffer.
|
|
//
|
|
|
|
pOutParam->Address = Base - (ULONG_PTR)(*MarshalledAuditParameters);
|
|
|
|
Base += PtrAlignSize( pInParam->Length );
|
|
|
|
ASSERT( (ULONG_PTR)Base <= (ULONG_PTR)(*MarshalledAuditParameters) + TotalSize );
|
|
|
|
break;
|
|
}
|
|
|
|
case SeAdtParmTypeStringList:
|
|
{
|
|
PLSA_ADT_STRING_LIST pSourceList = (PLSA_ADT_STRING_LIST)pInParam->Address;
|
|
PLSA_ADT_STRING_LIST pTargetList = (PLSA_ADT_STRING_LIST)Base;
|
|
PLSA_ADT_STRING_LIST_ENTRY pSourceEntry;
|
|
PLSA_ADT_STRING_LIST_ENTRY pTargetEntry;
|
|
PCHAR pBuffer;
|
|
ULONG e;
|
|
|
|
|
|
ASSERT(pSourceList);
|
|
|
|
|
|
//
|
|
// Let the data pointer in the output parameter
|
|
// 'point' to the new string structure.
|
|
//
|
|
|
|
pOutParam->Address = Base - (ULONG_PTR)(*MarshalledAuditParameters);
|
|
|
|
|
|
pTargetList->cStrings = pSourceList->cStrings;
|
|
|
|
Base += sizeof(LSA_ADT_STRING_LIST);
|
|
|
|
|
|
if (pSourceList->cStrings)
|
|
{
|
|
//
|
|
// Put the current offset into the Strings field.
|
|
//
|
|
|
|
pTargetList->Strings = (PLSA_ADT_STRING_LIST_ENTRY)(Base - (ULONG_PTR)(*MarshalledAuditParameters));
|
|
|
|
|
|
//
|
|
// Let pBuffer point to the area where we are
|
|
// going to store the string data.
|
|
//
|
|
|
|
pBuffer = Base + pSourceList->cStrings * sizeof(LSA_ADT_STRING_LIST_ENTRY);
|
|
|
|
|
|
//
|
|
// Walk through all the string entries and copy them.
|
|
//
|
|
|
|
for (
|
|
e = 0, pSourceEntry = pSourceList->Strings, pTargetEntry = (PLSA_ADT_STRING_LIST_ENTRY)Base;
|
|
e < pSourceList->cStrings;
|
|
e++, pSourceEntry++, pTargetEntry++)
|
|
{
|
|
//
|
|
// Copy the entry itself.
|
|
//
|
|
|
|
*pTargetEntry = *pSourceEntry;
|
|
|
|
|
|
//
|
|
// Fixup the Buffer field of the unicode string.
|
|
//
|
|
|
|
pTargetEntry->String.Buffer = (PWSTR)(pBuffer - (ULONG_PTR)(*MarshalledAuditParameters));
|
|
|
|
|
|
//
|
|
// Copy the string buffer.
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
pBuffer,
|
|
pSourceEntry->String.Buffer,
|
|
pSourceEntry->String.Length);
|
|
|
|
|
|
//
|
|
// Adjust pBuffer to point past the buffer just copied.
|
|
//
|
|
|
|
pBuffer += PtrAlignSize(pSourceEntry->String.Length);
|
|
}
|
|
|
|
|
|
//
|
|
// pBuffer now points past the end of the last string buffer.
|
|
// Use it to init Base for the next parameter.
|
|
//
|
|
|
|
Base = pBuffer;
|
|
}
|
|
|
|
ASSERT((ULONG_PTR)Base <= (ULONG_PTR)pTargetList + pInParam->Length);
|
|
ASSERT((ULONG_PTR)Base <= (ULONG_PTR)(*MarshalledAuditParameters) + TotalSize);
|
|
|
|
break;
|
|
}
|
|
|
|
case SeAdtParmTypeSidList:
|
|
{
|
|
PLSA_ADT_SID_LIST pSourceList = (PLSA_ADT_SID_LIST)pInParam->Address;
|
|
PLSA_ADT_SID_LIST pTargetList = (PLSA_ADT_SID_LIST)Base;
|
|
PLSA_ADT_SID_LIST_ENTRY pSourceEntry;
|
|
PLSA_ADT_SID_LIST_ENTRY pTargetEntry;
|
|
PCHAR pBuffer;
|
|
ULONG Length;
|
|
ULONG e;
|
|
|
|
ASSERT(pSourceList);
|
|
|
|
|
|
//
|
|
// Let the data pointer in the output parameter
|
|
// 'point' to the new string structure.
|
|
//
|
|
|
|
pOutParam->Address = Base - (ULONG_PTR)(*MarshalledAuditParameters);
|
|
|
|
pTargetList->cSids = pSourceList->cSids;
|
|
|
|
Base += sizeof(LSA_ADT_SID_LIST);
|
|
|
|
|
|
if (pSourceList->cSids)
|
|
{
|
|
//
|
|
// Put the current offset into the Sids field.
|
|
//
|
|
|
|
pTargetList->Sids = (PLSA_ADT_SID_LIST_ENTRY)(Base - (ULONG_PTR)(*MarshalledAuditParameters));
|
|
|
|
|
|
//
|
|
// Let pBuffer point to the area where we are
|
|
// going to store the sid data.
|
|
//
|
|
|
|
pBuffer = Base + pSourceList->cSids * sizeof(LSA_ADT_SID_LIST_ENTRY);
|
|
|
|
|
|
//
|
|
// Walk through all the sid entries and copy them.
|
|
//
|
|
|
|
for (
|
|
e = 0, pSourceEntry = pSourceList->Sids, pTargetEntry = (PLSA_ADT_SID_LIST_ENTRY)Base;
|
|
e < pSourceList->cSids;
|
|
e++, pSourceEntry++, pTargetEntry++)
|
|
{
|
|
//
|
|
// Copy the flags field.
|
|
//
|
|
|
|
pTargetEntry->Flags = pSourceEntry->Flags;
|
|
|
|
|
|
//
|
|
// Fixup the pointer to the sid.
|
|
//
|
|
|
|
pTargetEntry->Sid = (PSID)(pBuffer - (ULONG_PTR)(*MarshalledAuditParameters));
|
|
|
|
|
|
//
|
|
// Get the length of the sid.
|
|
//
|
|
|
|
Length = RtlLengthSid(pSourceEntry->Sid);
|
|
|
|
|
|
//
|
|
// Copy the sid.
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
pBuffer,
|
|
pSourceEntry->Sid,
|
|
Length);
|
|
|
|
|
|
//
|
|
// Adjust pBuffer to point past the sid just copied.
|
|
//
|
|
|
|
pBuffer += PtrAlignSize(Length);
|
|
}
|
|
|
|
|
|
//
|
|
// pBuffer now points past the end of the last sid.
|
|
// Use it to init Base for the next parameter.
|
|
//
|
|
|
|
Base = pBuffer;
|
|
}
|
|
|
|
ASSERT((ULONG_PTR)Base <= (ULONG_PTR)pTargetList + pInParam->Length);
|
|
ASSERT((ULONG_PTR)Base <= (ULONG_PTR)(*MarshalledAuditParameters) + TotalSize);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if ( *MarshalledAuditParameters )
|
|
{
|
|
LsapFreeLsaHeap( *MarshalledAuditParameters );
|
|
}
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapAdtInitParametersArray(
|
|
IN SE_ADT_PARAMETER_ARRAY* AuditParameters,
|
|
IN ULONG AuditCategoryId,
|
|
IN ULONG AuditId,
|
|
IN USHORT AuditEventType,
|
|
IN USHORT ParameterCount,
|
|
...)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes AuditParameters array in the format
|
|
required by the LsapAdtWriteLog function.
|
|
|
|
Arguments:
|
|
|
|
AuditParameters - pointer to audit parameters struct to be initialized
|
|
|
|
AuditCategoryId - audit category id
|
|
e.g. SE_CATEGID_OBJECT_ACCESS
|
|
|
|
AuditId - sub-type of audit
|
|
e.g. SE_AUDITID_OBJECT_OPERATION
|
|
|
|
AuditEventType - The type of audit event to be generated.
|
|
EVENTLOG_AUDIT_SUCCESS or EVENTLOG_AUDIT_FAILURE
|
|
|
|
ParameterCount - number of parameter pairs after this parameter
|
|
Each pair is in the form
|
|
<parameter type>, <parameter value>
|
|
e.g. SeAdtParmTypeString, <addr. of unicode string>
|
|
|
|
The only exception is for SeAdtParmTypeAccessMask which is
|
|
followed by <mask-value> and <index-to-object-type-entry>.
|
|
Refer to LsapAdtGenerateObjectOperationAuditEvent for an example.
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
va_list arglist;
|
|
UINT i;
|
|
|
|
PSE_ADT_PARAMETER_ARRAY_ENTRY Parameter;
|
|
SE_ADT_PARAMETER_TYPE ParameterType;
|
|
LUID Luid;
|
|
LARGE_INTEGER LargeInteger;
|
|
ULONGLONG Qword;
|
|
PPRIVILEGE_SET Privileges;
|
|
PUNICODE_STRING String;
|
|
PSID Sid;
|
|
LPGUID pGuid;
|
|
GUID NullGuid = { 0 };
|
|
USHORT ObjectTypeIndex;
|
|
PSOCKADDR pSockAddr = NULL;
|
|
|
|
|
|
RtlZeroMemory ( (PVOID) AuditParameters,
|
|
sizeof(SE_ADT_PARAMETER_ARRAY) );
|
|
|
|
AuditParameters->CategoryId = AuditCategoryId;
|
|
AuditParameters->AuditId = AuditId;
|
|
AuditParameters->Type = AuditEventType;
|
|
AuditParameters->ParameterCount = ParameterCount;
|
|
|
|
Parameter = AuditParameters->Parameters;
|
|
|
|
DsysAssertMsg( ParameterCount <= SE_MAX_AUDIT_PARAMETERS, "LsapAdtInitParametersArray" );
|
|
|
|
va_start (arglist, ParameterCount);
|
|
|
|
for (i=0; i<ParameterCount; i++) {
|
|
|
|
ParameterType = va_arg(arglist, SE_ADT_PARAMETER_TYPE);
|
|
|
|
Parameter->Type = ParameterType;
|
|
|
|
switch(ParameterType) {
|
|
|
|
//
|
|
// guard against somebody adding a new param type and not
|
|
// adding appropriate code here.
|
|
//
|
|
default:
|
|
ASSERT(FALSE && L"LsapAdtInitParametersArray: unknown param type");
|
|
break;
|
|
|
|
case SeAdtParmTypeNone:
|
|
break;
|
|
|
|
case SeAdtParmTypeFileSpec:
|
|
case SeAdtParmTypeString:
|
|
String = va_arg(arglist, PUNICODE_STRING);
|
|
|
|
if ( String )
|
|
{
|
|
Parameter->Length = sizeof(UNICODE_STRING)+String->Length;
|
|
Parameter->Address = String;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if the caller passed NULL, make type == none
|
|
// so that a '-' will be emitted in the eventlog
|
|
//
|
|
|
|
Parameter->Type = SeAdtParmTypeNone;
|
|
}
|
|
break;
|
|
|
|
case SeAdtParmTypeUserAccountControl:
|
|
Parameter->Length = 2 * sizeof(ULONG);
|
|
Parameter->Data[0] = va_arg(arglist, ULONG);
|
|
Parameter->Data[1] = va_arg(arglist, ULONG);
|
|
break;
|
|
|
|
case SeAdtParmTypeNoUac:
|
|
// no additional setting
|
|
break;
|
|
|
|
case SeAdtParmTypeHexUlong:
|
|
case SeAdtParmTypeUlong:
|
|
case SeAdtParmTypeMessage:
|
|
Parameter->Length = sizeof(ULONG);
|
|
Parameter->Data[0] = va_arg(arglist, ULONG);
|
|
break;
|
|
|
|
case SeAdtParmTypePtr:
|
|
Parameter->Length = sizeof(ULONG_PTR);
|
|
Parameter->Data[0] = va_arg(arglist, ULONG_PTR);
|
|
break;
|
|
|
|
case SeAdtParmTypeSid:
|
|
Sid = va_arg(arglist, PSID);
|
|
|
|
if ( Sid )
|
|
{
|
|
if ( !RtlValidSid( Sid ))
|
|
{
|
|
Status = STATUS_INVALID_SID;
|
|
goto Cleanup;
|
|
}
|
|
Parameter->Length = RtlLengthSid(Sid);
|
|
Parameter->Address = Sid;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if the caller passed NULL, make type == none
|
|
// so that a '-' will be emitted in the eventlog
|
|
//
|
|
|
|
Parameter->Type = SeAdtParmTypeNone;
|
|
}
|
|
break;
|
|
|
|
case SeAdtParmTypeGuid:
|
|
pGuid = va_arg(arglist, LPGUID);
|
|
|
|
//
|
|
// if the GUID is supplied and is not NULL-GUID store
|
|
// it as a GUID, otherwise mark as SeAdtParmTypeNone
|
|
// so that it will produce '-' in the formatted audit event.
|
|
//
|
|
if ( pGuid && memcmp( pGuid, &NullGuid, sizeof(GUID)))
|
|
{
|
|
Parameter->Length = sizeof(GUID);
|
|
Parameter->Address = pGuid;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if the caller passed NULL, make type == none
|
|
// so that a '-' will be emitted in the eventlog
|
|
//
|
|
|
|
Parameter->Type = SeAdtParmTypeNone;
|
|
}
|
|
break;
|
|
|
|
case SeAdtParmTypeSockAddr:
|
|
pSockAddr = va_arg(arglist, PSOCKADDR);
|
|
|
|
Parameter->Address = pSockAddr;
|
|
|
|
//
|
|
// currently we only support IPv4 and IPv6. for anything else
|
|
// the following will break
|
|
//
|
|
|
|
if ( pSockAddr )
|
|
{
|
|
if ( pSockAddr->sa_family == AF_INET6 )
|
|
{
|
|
Parameter->Length = sizeof(SOCKADDR_IN6);
|
|
}
|
|
else if ( pSockAddr->sa_family == AF_INET )
|
|
{
|
|
Parameter->Length = sizeof(SOCKADDR_IN);
|
|
}
|
|
else
|
|
{
|
|
Parameter->Length = sizeof(SOCKADDR);
|
|
|
|
//
|
|
// sa_family == 0 is a valid way of specifying that
|
|
// the sock addr is not specified.
|
|
//
|
|
|
|
if ( pSockAddr->sa_family != 0 )
|
|
{
|
|
AdtAssert(FALSE, ("LsapAdtInitParametersArray: invalid sa_family: %d", pSockAddr->sa_family));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SeAdtParmTypeLogonId:
|
|
case SeAdtParmTypeLuid:
|
|
Luid = va_arg(arglist, LUID);
|
|
Parameter->Length = sizeof(LUID);
|
|
*((LUID*) Parameter->Data) = Luid;
|
|
break;
|
|
|
|
case SeAdtParmTypeTime:
|
|
case SeAdtParmTypeDuration:
|
|
case SeAdtParmTypeDateTime:
|
|
LargeInteger = va_arg(arglist, LARGE_INTEGER);
|
|
Parameter->Length = sizeof(LARGE_INTEGER);
|
|
*((PLARGE_INTEGER) Parameter->Data) = LargeInteger;
|
|
break;
|
|
|
|
case SeAdtParmTypeHexInt64:
|
|
Qword = va_arg(arglist, ULONGLONG);
|
|
Parameter->Length = sizeof(ULONGLONG);
|
|
*((PULONGLONG) Parameter->Data) = Qword;
|
|
break;
|
|
|
|
case SeAdtParmTypeNoLogonId:
|
|
// no additional setting
|
|
break;
|
|
|
|
case SeAdtParmTypeAccessMask:
|
|
Parameter->Length = sizeof(ACCESS_MASK);
|
|
Parameter->Data[0] = va_arg(arglist, ACCESS_MASK);
|
|
ObjectTypeIndex = va_arg(arglist, USHORT);
|
|
DsysAssertMsg((ObjectTypeIndex < i), "LsapAdtInitParametersArray");
|
|
Parameter->Data[1] = ObjectTypeIndex;
|
|
break;
|
|
|
|
case SeAdtParmTypePrivs:
|
|
Privileges = va_arg(arglist, PPRIVILEGE_SET);
|
|
|
|
if (!IsValidPrivilegeCount(Privileges->PrivilegeCount))
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
Parameter->Length = LsapPrivilegeSetSize(Privileges);
|
|
break;
|
|
|
|
case SeAdtParmTypeObjectTypes:
|
|
{
|
|
ULONG ObjectTypeCount;
|
|
|
|
Parameter->Address = va_arg(arglist, PSE_ADT_OBJECT_TYPE);
|
|
ObjectTypeCount = va_arg(arglist, ULONG);
|
|
Parameter->Length = sizeof(SE_ADT_OBJECT_TYPE)*ObjectTypeCount;
|
|
Parameter->Data[1] = va_arg(arglist, ULONG);
|
|
}
|
|
break;
|
|
|
|
case SeAdtParmTypeStringList:
|
|
{
|
|
PLSA_ADT_STRING_LIST pList;
|
|
|
|
pList = va_arg(arglist, PLSA_ADT_STRING_LIST);
|
|
|
|
if (pList)
|
|
{
|
|
Parameter->Address = pList;
|
|
Parameter->Length = LsapStringListSize(pList);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if the caller passed NULL, make type == none
|
|
// so that a '-' will be emitted in the eventlog
|
|
//
|
|
|
|
Parameter->Type = SeAdtParmTypeNone;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SeAdtParmTypeSidList:
|
|
{
|
|
PLSA_ADT_SID_LIST pList;
|
|
|
|
pList = va_arg(arglist, PLSA_ADT_SID_LIST);
|
|
|
|
if (pList)
|
|
{
|
|
Parameter->Address = pList;
|
|
Parameter->Length = LsapSidListSize(pList);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if the caller passed NULL, make type == none
|
|
// so that a '-' will be emitted in the eventlog
|
|
//
|
|
|
|
Parameter->Type = SeAdtParmTypeNone;
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
Parameter++;
|
|
}
|
|
|
|
va_end(arglist);
|
|
|
|
Cleanup:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
LsapStringListSize(
|
|
IN PLSA_ADT_STRING_LIST pStringList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the total number of bytes needed to store
|
|
a string list as a blob when marshalling it.
|
|
|
|
Arguments:
|
|
|
|
pStringList - pointer to the string list
|
|
|
|
Return Value:
|
|
|
|
Number of bytes needed
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
ULONG Size = 0;
|
|
ULONG i;
|
|
PLSA_ADT_STRING_LIST_ENTRY pEntry;
|
|
|
|
if (pStringList)
|
|
{
|
|
Size += sizeof(LSA_ADT_STRING_LIST);
|
|
|
|
Size += pStringList->cStrings * sizeof(LSA_ADT_STRING_LIST_ENTRY);
|
|
|
|
for (i=0,pEntry=pStringList->Strings;i < pStringList->cStrings;i++,pEntry++)
|
|
{
|
|
Size += PtrAlignSize(pEntry->String.Length);
|
|
}
|
|
}
|
|
|
|
return Size;
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
LsapSidListSize(
|
|
IN PLSA_ADT_SID_LIST pSidList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the total number of bytes needed to store
|
|
a sid list as a blob when marshalling it.
|
|
|
|
Arguments:
|
|
|
|
pSidList - pointer to the sid list
|
|
|
|
Return Value:
|
|
|
|
Number of bytes needed
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
ULONG Size = 0;
|
|
ULONG i;
|
|
PLSA_ADT_SID_LIST_ENTRY pEntry;
|
|
|
|
if (pSidList)
|
|
{
|
|
Size += sizeof(LSA_ADT_SID_LIST);
|
|
|
|
Size += pSidList->cSids * sizeof(LSA_ADT_SID_LIST_ENTRY);
|
|
|
|
for (i=0,pEntry=pSidList->Sids;i < pSidList->cSids;i++,pEntry++)
|
|
{
|
|
ASSERT(RtlValidSid(pEntry->Sid));
|
|
|
|
Size += PtrAlignSize(RtlLengthSid(pEntry->Sid));
|
|
}
|
|
}
|
|
|
|
return Size;
|
|
}
|