Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2620 lines
73 KiB

#include "pch.h"
#pragma hdrstop
#if !defined(lint)
#include "lsaptmp.h"
#include "adttest.h"
LUID AuditPrivilege = { SE_AUDIT_PRIVILEGE, 0 };
NTSTATUS
LsapGetLogonSessionAccountInfo(
IN PLUID Value,
OUT PUNICODE_STRING AccountName,
OUT PUNICODE_STRING AuthorityName
);
NTSTATUS
LsapRtlConvertSidToString(
IN PSID Sid,
OUT PWSTR szString,
IN OUT DWORD *pdwRequiredSize
)
{
NTSTATUS Status = STATUS_SUCCESS;
PWSTR szBufPtr = szString;
ULONG ulNumChars;
UCHAR i;
ULONG Tmp;
PISID iSid = (PISID)Sid;
if ( *pdwRequiredSize < 256 )
{
Status = STATUS_BUFFER_OVERFLOW;
*pdwRequiredSize = 256;
goto Cleanup;
}
ulNumChars = wsprintf(szBufPtr, L"S-%u-", (USHORT)iSid->Revision );
szBufPtr += ulNumChars;
if ( (iSid->IdentifierAuthority.Value[0] != 0) ||
(iSid->IdentifierAuthority.Value[1] != 0) )
{
ulNumChars = wsprintf(szBufPtr, L"0x%02hx%02hx%02hx%02hx%02hx%02hx",
(USHORT)iSid->IdentifierAuthority.Value[0],
(USHORT)iSid->IdentifierAuthority.Value[1],
(USHORT)iSid->IdentifierAuthority.Value[2],
(USHORT)iSid->IdentifierAuthority.Value[3],
(USHORT)iSid->IdentifierAuthority.Value[4],
(USHORT)iSid->IdentifierAuthority.Value[5] );
}
else
{
Tmp = (ULONG)iSid->IdentifierAuthority.Value[5] +
(ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
(ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
(ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
ulNumChars = wsprintf(szBufPtr, L"%lu", Tmp);
}
szBufPtr += ulNumChars;
for (i=0;i<iSid->SubAuthorityCount ;i++ )
{
ulNumChars = wsprintf(szBufPtr, L"-%lu", iSid->SubAuthority[i]);
szBufPtr += ulNumChars;
}
Cleanup:
return(Status);
}
PVOID NTAPI
LsapAllocateLsaHeap(
IN ULONG cbMemory
)
{
return(RtlAllocateHeap(
RtlProcessHeap(),
HEAP_ZERO_MEMORY,
cbMemory
));
}
void NTAPI
LsapFreeLsaHeap(
IN PVOID pvMemory
)
{
RtlFreeHeap(RtlProcessHeap(), 0, pvMemory);
}
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;
//
// Initialization.
//
RtlInitUnicodeString( &NewObjectTypeName, NULL );
Status= LsapAdtBuildDashString(
&DashString,
&FreeDash
);
if ( !NT_SUCCESS( Status )) {
return( Status );
}
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 ) {
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 {
//
// Couldn't allocate memory for that string,
// use the Dash string that we've already created.
//
StringPointerArray[StringIndex] = &DashString;
FreeWhenDone[StringIndex] = FALSE;
}
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 {
//
// Couldn't allocate memory for that string,
// use the Dash string that we've already created.
//
StringPointerArray[StringIndex] = &DashString;
FreeWhenDone[StringIndex] = FALSE;
}
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 {
//
// Couldn't allocate memory for that string,
// use the Dash string that we've already created.
//
StringPointerArray[StringIndex] = &DashString;
FreeWhenDone[StringIndex] = FALSE;
}
StringIndex++;
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 {
//
// Do nothing, fall through to the NoLogonId case
//
}
}
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];
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 {
//
// That didn't work, use the Dash string instead.
//
StringPointerArray[ StringIndex ] = &DashString;
FreeWhenDone [ StringIndex ] = FALSE;
}
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 {
//
// That didn't work, use the Dash string instead.
//
StringPointerArray[ StringIndex ] = &DashString;
FreeWhenDone [ StringIndex ] = FALSE;
}
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];
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.
Status = LsapAdtBuildObjectTypeStrings(
SourceModule,
ObjectTypeName,
ObjectTypeList,
ObjectTypeCount,
&StringArray [ StringIndex ],
&FreeWhenDone[ StringIndex ],
&NewObjectTypeName
);
for (j=0; j<10; 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 {
//
// Couldn't allocate memory for that string,
// use the Dash string that we've already created.
//
StringPointerArray[StringIndex] = &DashString;
FreeWhenDone[StringIndex] = FALSE;
}
StringIndex++;
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;
}
//
// Probably have to do this from somewhere else eventually, but for now
// do it from here.
//
Status = kElfReportEventW (
NULL, //LsapAdtLogHandle,
AuditParameters->Type,
(USHORT)AuditParameters->CategoryId,
AuditParameters->AuditId,
UserSid,
StringIndex,
0,
StringPointerArray,
NULL,
0,
NULL,
NULL
);
//
// cleanup
//
for (i=0; i<StringIndex; i++) {
if (FreeWhenDone[i]) {
LsapFreeLsaHeap( StringPointerArray[i]->Buffer );
}
}
//
// 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)) &&
TRUE /*LsapState.SystemShutdownPending*/ ) {
Status = STATUS_SUCCESS;
}
return( Status );
}
// ======================================================================
// adtbuild.c
// ======================================================================
////////////////////////////////////////////////////////////////////////
// //
// Local Macro definitions and local function prototypes //
// //
////////////////////////////////////////////////////////////////////////
#ifdef LSAP_ADT_UMTEST
//
// Define all external routines that we won't pick up in a user mode test
//
// NTSTATUS
// LsapGetLogonSessionAccountInfo(
// IN PLUID Value,
// OUT PUNICODE_STRING AccountName,
// OUT PUNICODE_STRING AuthorityName
// );
#endif
////////////////////////////////////////////////////////////////////////
// //
// Data types used within this module //
// //
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// //
// Variables global within this module //
// //
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// //
// Services exported by this module. //
// //
////////////////////////////////////////////////////////////////////////
NTSTATUS
LsapAdtBuildUlongString(
IN ULONG Value,
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone
)
/*++
Routine Description:
This function builds a unicode string representing the passed value.
The resultant string will be formatted as a decimal value with not
more than 10 digits.
Arguments:
Value - The value to be transformed to printable format (Unicode string).
ResultantString - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
for the string body.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status;
//
// Maximum length is 10 wchar characters plus a null termination character.
//
ResultantString->Length = 0;
ResultantString->MaximumLength = 11 * sizeof(WCHAR); // 10 digits & null termination
ResultantString->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0,
ResultantString->MaximumLength);
if (ResultantString->Buffer == NULL) {
return(STATUS_NO_MEMORY);
}
Status = RtlIntegerToUnicodeString( Value, 10, ResultantString );
ASSERT(NT_SUCCESS(Status));
(*FreeWhenDone) = TRUE;
return(STATUS_SUCCESS);
}
NTSTATUS
LsapAdtBuildHexUlongString(
IN ULONG Value,
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone
)
/*++
Routine Description:
This function builds a unicode string representing the passed value.
The resultant string will be formatted as a hexidecimal value with not
more than 10 digits.
Arguments:
Value - The value to be transformed to printable format (Unicode string).
ResultantString - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
for the string body.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status;
//
// Maximum length is 10 wchar characters plus a null termination character.
//
ResultantString->Length = 0;
ResultantString->MaximumLength = 11 * sizeof(WCHAR); // 8 digits, a 0x, & null termination
ResultantString->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0,
ResultantString->MaximumLength);
if (ResultantString->Buffer == NULL) {
return(STATUS_NO_MEMORY);
}
ResultantString->Buffer[0] = L'0';
ResultantString->Buffer[1] = L'x';
ResultantString->Buffer += 2;
Status = RtlIntegerToUnicodeString( Value, 16, ResultantString );
ASSERT(NT_SUCCESS(Status));
//
// Subtract off the two
//
ResultantString->Buffer -= 2;
ResultantString->Length += 2 * sizeof(WCHAR);
(*FreeWhenDone) = TRUE;
return(STATUS_SUCCESS);
}
NTSTATUS
LsapAdtBuildPtrString(
IN PVOID Value,
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone
)
/*++
Routine Description:
This function builds a unicode string representing the passed pointer.
The resultant string will be formatted as a hexidecimal value.
Arguments:
Value - The value to be transformed to printable format (Unicode string).
ResultantString - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
for the string body.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
USHORT NumChars;
ResultantString->Length = 0;
//
// Maximum length: 0x + 16 digit hex + null + 1 bonus == 20 chars
//
ResultantString->MaximumLength = 20 * sizeof(WCHAR);
ResultantString->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0,
ResultantString->MaximumLength);
if (ResultantString->Buffer == NULL) {
Status = STATUS_NO_MEMORY;
} else {
NumChars = (USHORT) wsprintf( ResultantString->Buffer, L"0x%p", Value );
ResultantString->Length = NumChars * sizeof(WCHAR);
(*FreeWhenDone) = TRUE;
}
return Status;
}
NTSTATUS
LsapAdtBuildLuidString(
IN PLUID Value,
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone
)
/*++
Routine Description:
This function builds a unicode string representing the passed LUID.
The resultant string will be formatted as follows:
(0x00005678,0x12340000)
Arguments:
Value - The value to be transformed to printable format (Unicode string).
ResultantString - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
for the string body.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status;
UNICODE_STRING IntegerString;
ULONG Buffer[(16*sizeof(WCHAR))/sizeof(ULONG)];
IntegerString.Buffer = (PWCHAR)&Buffer[0];
IntegerString.MaximumLength = 16*sizeof(WCHAR);
//
// Length (in WCHARS) is 3 for (0x
// 10 for 1st hex number
// 3 for ,0x
// 10 for 2nd hex number
// 1 for )
// 1 for null termination
//
ResultantString->Length = 0;
ResultantString->MaximumLength = 28 * sizeof(WCHAR);
ResultantString->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0,
ResultantString->MaximumLength);
if (ResultantString->Buffer == NULL) {
return(STATUS_NO_MEMORY);
}
Status = RtlAppendUnicodeToString( ResultantString, L"(0x" );
ASSERT(NT_SUCCESS(Status));
Status = RtlIntegerToUnicodeString( Value->HighPart, 16, &IntegerString );
ASSERT(NT_SUCCESS(Status));
Status = RtlAppendUnicodeToString( ResultantString, IntegerString.Buffer );
ASSERT(NT_SUCCESS(Status));
Status = RtlAppendUnicodeToString( ResultantString, L",0x" );
ASSERT(NT_SUCCESS(Status));
Status = RtlIntegerToUnicodeString( Value->LowPart, 16, &IntegerString );
ASSERT(NT_SUCCESS(Status));
Status = RtlAppendUnicodeToString( ResultantString, IntegerString.Buffer );
ASSERT(NT_SUCCESS(Status));
Status = RtlAppendUnicodeToString( ResultantString, L")" );
ASSERT(NT_SUCCESS(Status));
(*FreeWhenDone) = TRUE;
return(STATUS_SUCCESS);
}
NTSTATUS
LsapAdtBuildSidString(
IN PSID Value,
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone
)
/*++
Routine Description:
This function builds a unicode string representing the passed LUID.
The resultant string will be formatted as follows:
S-1-281736-12-72-9-110
^ ^^ ^^ ^ ^^^
| | | | |
+-----+--+-+--+---- Decimal
Arguments:
Value - The value to be transformed to printable format (Unicode string).
ResultantString - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
for the string body.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status=STATUS_NO_MEMORY;
LPWSTR UniBuffer=NULL;
USHORT Len;
USHORT MaxLen;
*FreeWhenDone = FALSE;
//
// Note: RtlConvertSidToUnicodeString also uses a hard-coded const 256
// to generate the string SID.
//
MaxLen = (256+3) * sizeof(WCHAR);
UniBuffer = LsapAllocateLsaHeap(MaxLen);
if (UniBuffer)
{
ResultantString->Buffer = UniBuffer+2;
ResultantString->MaximumLength = MaxLen;
Status = RtlConvertSidToUnicodeString( ResultantString, Value, FALSE );
if (Status == STATUS_SUCCESS)
{
*FreeWhenDone = TRUE;
UniBuffer[0] = L'%';
UniBuffer[1] = L'{';
Len = ResultantString->Length / sizeof(WCHAR);
UniBuffer[Len+2] = L'}';
UniBuffer[Len+3] = UNICODE_NULL;
ResultantString->Buffer = UniBuffer;
ResultantString->Length = (Len+3)*sizeof(WCHAR);
}
else
{
LsapFreeLsaHeap(UniBuffer);
}
}
return(Status);
}
NTSTATUS
LsapAdtBuildDashString(
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone
)
/*++
Routine Description:
This function returns a string containing a dash ("-").
This is commonly used to represent "No value" in audit records.
Arguments:
ResultantString - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
Return Values:
STATUS_SUCCESS only.
--*/
{
RtlInitUnicodeString(ResultantString, L"-");
(*FreeWhenDone) = FALSE;
return STATUS_SUCCESS;
}
NTSTATUS
LsapAdtBuildFilePathString(
IN PUNICODE_STRING Value,
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone
)
/*++
Routine Description:
This function builds a unicode string representing the passed file
path name. If possible, the string will be generated using drive
letters instead of object architecture namespace.
Arguments:
Value - The original file path name. This is expected (but does not
have to be) a standard NT object architecture name-space pathname.
ResultantString - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
for the string body.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
//
// For now, don't do the conversion.
// Do this if we have time before we ship.
//
ResultantString->Length = Value->Length;
ResultantString->Buffer = Value->Buffer;
ResultantString->MaximumLength = Value->MaximumLength;
(*FreeWhenDone) = FALSE;
return(Status);
}
NTSTATUS
LsapAdtBuildLogonIdStrings(
IN PLUID LogonId,
OUT PUNICODE_STRING ResultantString1,
OUT PBOOLEAN FreeWhenDone1,
OUT PUNICODE_STRING ResultantString2,
OUT PBOOLEAN FreeWhenDone2,
OUT PUNICODE_STRING ResultantString3,
OUT PBOOLEAN FreeWhenDone3
)
/*++
Routine Description:
This function builds a 3 unicode strings representing the specified
logon ID. These strings will contain the username, domain, and
LUID string of the specified logon session (respectively).
Arguments:
Value - The logon ID.
ResultantString1 - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
This parameter will contain the username.
FreeWhenDone1 - If TRUE, indicates that the body of ResultantString1
must be freed to process heap when no longer needed.
ResultantString2 - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
This parameter will contain the username.
FreeWhenDone2 - If TRUE, indicates that the body of ResultantString2
must be freed to process heap when no longer needed.
ResultantString3 - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
This parameter will contain the username.
FreeWhenDone3 - If TRUE, indicates that the body of ResultantString3
must be freed to process heap when no longer needed.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
for the string body.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status;
UNICODE_STRING DashString;
BOOLEAN FreeDash;
//
// Try to convert the LUID first.
//
Status= LsapAdtBuildDashString(
&DashString,
&FreeDash
);
if ( !NT_SUCCESS( Status )) {
return( Status );
}
Status = LsapAdtBuildLuidString( LogonId, ResultantString3, FreeWhenDone3 );
if (NT_SUCCESS(Status)) {
// *ResultantString1 = DashString;
// *ResultantString2 = DashString;
*FreeWhenDone1 = FALSE;
*FreeWhenDone2 = FALSE;
//
// Now get the username and domain names
//
Status = LsapGetLogonSessionAccountInfo( LogonId,
ResultantString1,
ResultantString2
);
if (NT_SUCCESS(Status)) {
// (*FreeWhenDone1) = TRUE;
// (*FreeWhenDone2) = TRUE;
} else {
//
// The LUID may be the system LUID
//
LUID SystemLuid = SYSTEM_LUID;
if ( RtlEqualLuid( LogonId, &SystemLuid )) {
RtlInitUnicodeString(ResultantString1, L"SYSTEM");
RtlInitUnicodeString(ResultantString2, L"SYSTEM");
(*FreeWhenDone1) = FALSE;
(*FreeWhenDone2) = FALSE;
Status = STATUS_SUCCESS;
} else {
//
// We have no clue what this is, just free what we've
// allocated.
//
if ((FreeWhenDone3)) {
LsapFreeLsaHeap( ResultantString3->Buffer );
}
}
}
}
return(Status);
}
////////////////////////////////////////////////////////////////////////
// //
// Services private to this module. //
// //
////////////////////////////////////////////////////////////////////////
//
// Define this routine only for user mode test
//
NTSTATUS
LsapGetLogonSessionAccountInfo(
IN PLUID Value,
OUT PUNICODE_STRING AccountName,
OUT PUNICODE_STRING AuthorityName
)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
HRESULT hr;
SECURITY_USER_DATA* pUserData;
hr = GetSecurityUserInfo( Value, 0, &pUserData );
if (SUCCEEDED(hr))
{
Status = STATUS_SUCCESS;
*AccountName = pUserData->UserName;
*AuthorityName = pUserData->LogonDomainName;
}
return(Status);
}
// ======================================================================
// from adtobjs.c
// ======================================================================
#define LSAP_ADT_OBJECT_TYPE_STRINGS 10
#define LSAP_ADT_ACCESS_NAME_FORMATTING L"\r\n\t\t\t"
#define LSAP_ADT_ACCESS_NAME_FORMATTING_TAB L"\t"
#define LSAP_ADT_ACCESS_NAME_FORMATTING_NL L"\r\n"
UNICODE_STRING LsapAdtEventIdStringDelete,
LsapAdtEventIdStringReadControl,
LsapAdtEventIdStringWriteDac,
LsapAdtEventIdStringWriteOwner,
LsapAdtEventIdStringSynchronize,
LsapAdtEventIdStringAccessSysSec,
LsapAdtEventIdStringMaxAllowed,
LsapAdtEventIdStringSpecific[16];
#define LsapAdtSourceModuleLock() 0
#define LsapAdtSourceModuleUnlock() 0
//
// Each event source is represented by a source module descriptor.
// These are kept on a linked list (LsapAdtSourceModules).
//
typedef struct _LSAP_ADT_OBJECT {
//
// Pointer to next source module descriptor
// This is assumed to be the first field in the structure.
//
struct _LSAP_ADT_OBJECT *Next;
//
// Name of object
//
UNICODE_STRING Name;
//
// Base offset of specific access types
//
ULONG BaseOffset;
} LSAP_ADT_OBJECT, *PLSAP_ADT_OBJECT;
//
// Each event source is represented by a source module descriptor.
// These are kept on a linked list (LsapAdtSourceModules).
//
typedef struct _LSAP_ADT_SOURCE {
//
// Pointer to next source module descriptor
// This is assumed to be the first field in the structure.
//
struct _LSAP_ADT_SOURCE *Next;
//
// Name of source module
//
UNICODE_STRING Name;
//
// list of objects
//
PLSAP_ADT_OBJECT Objects;
} LSAP_ADT_SOURCE, *PLSAP_ADT_SOURCE;
PLSAP_ADT_SOURCE LsapAdtSourceModules;
NTSTATUS
LsapDsGuidToString(
IN GUID *ObjectType,
IN PUNICODE_STRING UnicodeString
)
/*++
Routine Description:
This routine converts a GUID to a string. The GUID is one of the following:
Class Guid indicating the class of an object.
Property Set Guid identifying a property set.
Property Guid identifying a property.
In each case, the routine returns a text string naming the object/property
set or property.
If the passed in GUID is cannot be found in the schema,
the GUID will simply be converted to a text string.
Arguments:
ObjectType - Specifies the GUID to translate.
UnicodeString - Returns the text string.
Return Values:
STATUS_NO_MEMORY - Not enough memory to allocate string.
--*/
{
NTSTATUS Status;
RPC_STATUS RpcStatus;
LPWSTR GuidString = NULL;
ULONG GuidStringSize;
ULONG GuidStringLen;
LPWSTR LocalGuidString;
//
// Convert the GUID to text
//
RpcStatus = UuidToStringW( ObjectType,
&GuidString );
if ( RpcStatus != RPC_S_OK ) {
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
GuidStringLen = wcslen( GuidString );
GuidStringSize = (GuidStringLen + 4) * sizeof(WCHAR);
LocalGuidString = LsapAllocateLsaHeap( GuidStringSize );
if ( LocalGuidString == NULL ) {
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
LocalGuidString[0] = L'%';
LocalGuidString[1] = L'{';
RtlCopyMemory( &LocalGuidString[2], GuidString, GuidStringLen*sizeof(WCHAR) );
LocalGuidString[GuidStringLen+2] = L'}';
LocalGuidString[GuidStringLen+3] = L'\0';
RtlInitUnicodeString( UnicodeString, LocalGuidString );
Status = STATUS_SUCCESS;
Cleanup:
if ( GuidString != NULL ) {
RpcStringFreeW( &GuidString );
}
return Status;
}
NTSTATUS
LsapAdtAppendString(
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone,
IN PUNICODE_STRING StringToAppend,
IN PULONG StringIndex
)
/*++
Routine Description:
This function appends a string to the next available of the LSAP_ADT_OBJECT_TYPE_STRINGS unicode
output strings.
Arguments:
ResultantString - Points to an array of LSAP_ADT_OBJECT_TYPE_STRINGS unicode string headers. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
StringToAppend - String to be appended to ResultantString.
StringIndex - Index to the current ResultantString to be used.
Passes in an index to the resultant string to use.
Passes out the index to the resultant string being used.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
to store the object information.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status;
UNICODE_STRING SourceString;
ULONG Index;
// Must be multiple of sizeof(WCHAR)
#define ADT_MAX_STRING 0xFFFE
//
// Initialization.
//
SourceString = *StringToAppend;
Index = *StringIndex;
//
// If all of the strings are already full,
// early out.
//
if ( Index >= LSAP_ADT_OBJECT_TYPE_STRINGS ) {
return STATUS_SUCCESS;
}
//
// Loop until the source string is completely appended.
//
while ( SourceString.Length ) {
//
// If the destination string has room,
// append to it.
//
if ( FreeWhenDone[Index] && ResultantString[Index].Length != ADT_MAX_STRING ){
UNICODE_STRING SubString;
USHORT RoomLeft;
//
// If the Source String is a replacement string,
// make sure we don't split it across a ResultantString boundary
//
RoomLeft = ResultantString[Index].MaximumLength -
ResultantString[Index].Length;
if ( SourceString.Buffer[0] != L'%' ||
RoomLeft >= SourceString.Length ) {
//
// Compute the substring that fits.
//
SubString.Length = min( RoomLeft, SourceString.Length );
SubString.Buffer = SourceString.Buffer;
SourceString.Length -= SubString.Length;
SourceString.Buffer = (LPWSTR)(((LPBYTE)SourceString.Buffer) + SubString.Length);
//
// Append the substring onto the destination.
//
Status = RtlAppendUnicodeStringToString(
&ResultantString[Index],
&SubString );
ASSERT(NT_SUCCESS(Status));
}
}
//
// If there's more to copy,
// grow the buffer.
//
if ( SourceString.Length ) {
ULONG NewSize;
LPWSTR NewBuffer;
//
// If the current buffer is full,
// move to the next buffer.
//
if ( ResultantString[Index].Length == ADT_MAX_STRING ) {
//
// If ALL of the buffers are full,
// silently return to the caller.
//
Index ++;
if ( Index >= LSAP_ADT_OBJECT_TYPE_STRINGS ) {
*StringIndex = Index;
return STATUS_SUCCESS;
}
}
//
// Allocate a buffer suitable for both the old string and the new one.
//
// Allocate the buffer at least large enough for the new string.
// Always grow the buffer in 1Kb chunks.
// Don't allocate larger than the maximum allowed size.
//
NewSize = max( ResultantString[Index].MaximumLength + 1024,
SourceString.Length );
NewSize = min( NewSize, ADT_MAX_STRING );
NewBuffer = LsapAllocateLsaHeap( NewSize );
if ( NewBuffer == NULL ) {
*StringIndex = Index;
return STATUS_NO_MEMORY;
}
//
// Copy the old buffer into the new buffer.
//
if ( ResultantString[Index].Buffer != NULL ) {
RtlCopyMemory( NewBuffer,
ResultantString[Index].Buffer,
ResultantString[Index].Length );
if ( FreeWhenDone[Index] ) {
LsapFreeLsaHeap( ResultantString[Index].Buffer );
}
}
ResultantString[Index].Buffer = NewBuffer;
ResultantString[Index].MaximumLength = (USHORT) NewSize;
FreeWhenDone[Index] = TRUE;
}
}
*StringIndex = Index;
return STATUS_SUCCESS;
}
NTSTATUS
LsapAdtAppendZString(
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone,
IN LPWSTR StringToAppend,
IN PULONG StringIndex
)
/*++
Routine Description:
Same as LsapAdpAppendString but takes a zero terminated string.
Arguments:
Same as LsapAdpAppendString but takes a zero terminated string.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
to store the object information.
All other Result Codes are generated by called routines.
--*/
{
UNICODE_STRING UnicodeString;
RtlInitUnicodeString( &UnicodeString, StringToAppend );
return LsapAdtAppendString( ResultantString,
FreeWhenDone,
&UnicodeString,
StringIndex );
}
ULONG
__cdecl
CompareObjectTypes(
const void * Param1,
const void * Param2
)
/*++
Routine Description:
Qsort comparison routine for sorting an object type array by access mask.
--*/
{
const SE_ADT_OBJECT_TYPE *ObjectType1 = Param1;
const SE_ADT_OBJECT_TYPE *ObjectType2 = Param2;
return ObjectType1->AccessMask - ObjectType2->AccessMask;
}
NTSTATUS
LsapAdtBuildObjectTypeStrings(
IN PUNICODE_STRING SourceModule,
IN PUNICODE_STRING ObjectTypeName,
IN PSE_ADT_OBJECT_TYPE ObjectTypeList,
IN ULONG ObjectTypeCount,
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone,
OUT PUNICODE_STRING NewObjectTypeName
)
/*++
Routine Description:
This function builds a LSAP_ADT_OBJECT_TYPE_STRINGS unicode strings containing parameter
file replacement parameters (e.g. %%1043) and Object GUIDs separated by carriage
return and tab characters suitable for display via the event viewer.
The buffers returned by this routine must be deallocated when no
longer needed if FreeWhenDone is true.
Arguments:
SourceModule - The module (ala event viewer modules) defining the
object type.
ObjectTypeName - The type of object to which the access mask applies.
ObjectTypeList - List of objects being granted access.
ObjectTypeCount - Number of objects in ObjectTypeList.
ResultantString - Points to an array of LSAP_ADT_OBJECT_TYPE_STRINGS unicode string headers. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
NewObjectTypeName - Returns a new name for the object type if one is
available.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
to store the object information.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status;
UNICODE_STRING LocalString;
LPWSTR GuidString;
UNICODE_STRING DsSourceName;
UNICODE_STRING DsObjectTypeName;
BOOLEAN LocalFreeWhenDone;
ULONG ResultantStringIndex = 0;
ULONG i;
ACCESS_MASK PreviousAccessMask;
ULONG Index;
BOOLEAN IsDs;
USHORT IndentLevel;
static LPWSTR Tabs[] =
{
L"\t",
L"\t\t",
L"\t\t\t",
L"\t\t\t\t"
};
USHORT cTabs = sizeof(Tabs) / sizeof(LPWSTR);
//
// Initialize all LSAP_ADT_OBJECT_TYPE_STRINGS buffers to empty strings
//
for ( i=0; i<LSAP_ADT_OBJECT_TYPE_STRINGS; i++ ) {
RtlInitUnicodeString( &ResultantString[i], L"" );
FreeWhenDone[i] = FALSE;
}
//
// If there are no objects,
// we're done.
//
if ( ObjectTypeCount == 0 ) {
return STATUS_SUCCESS;
}
//
// Determine if this entry is for the DS.
//
RtlInitUnicodeString( &DsSourceName, ACCESS_DS_SOURCE_W );
RtlInitUnicodeString( &DsObjectTypeName, ACCESS_DS_OBJECT_TYPE_NAME_W );
IsDs = RtlEqualUnicodeString( SourceModule, &DsSourceName, TRUE) &&
RtlEqualUnicodeString( ObjectTypeName, &DsObjectTypeName, TRUE);
//
// Group the objects with like access masks together.
// (Simply sort them).
//
qsort( ObjectTypeList,
ObjectTypeCount,
sizeof(SE_ADT_OBJECT_TYPE),
CompareObjectTypes );
//
// Loop through the objects outputting a line for each one.
//
PreviousAccessMask = ObjectTypeList[0].AccessMask -1;
for ( Index=0; Index<ObjectTypeCount; Index++ ) {
if ( IsDs &&
ObjectTypeList[Index].Level == ACCESS_OBJECT_GUID &&
NewObjectTypeName->Length == 0 ) {
(VOID) LsapDsGuidToString( &ObjectTypeList[Index].ObjectType,
NewObjectTypeName );
}
//
// If this entry simply represents the object itself,
// skip it.
if ( ObjectTypeList[Index].Flags & SE_ADT_OBJECT_ONLY ) {
continue;
}
//
// If this access mask is different than the one for the previous
// object,
// output a new copy of the access mask.
//
if ( ObjectTypeList[Index].AccessMask != PreviousAccessMask ) {
PreviousAccessMask = ObjectTypeList[Index].AccessMask;
if ( ObjectTypeList[Index].AccessMask == 0 ) {
RtlInitUnicodeString( &LocalString,
L"---" LSAP_ADT_ACCESS_NAME_FORMATTING_NL );
LocalFreeWhenDone = FALSE;
} else {
//
// Build a string with the access mask in it.
//
Status = LsapAdtBuildAccessesString(
SourceModule,
ObjectTypeName,
ObjectTypeList[Index].AccessMask,
FALSE,
&LocalString,
&LocalFreeWhenDone );
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
}
//
// Append it to the output string.
//
Status = LsapAdtAppendString(
ResultantString,
FreeWhenDone,
&LocalString,
&ResultantStringIndex );
if ( LocalFreeWhenDone ) {
LsapFreeLsaHeap( LocalString.Buffer );
}
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
}
IndentLevel = ObjectTypeList[Index].Level;
if (IndentLevel >= cTabs) {
IndentLevel = cTabs-1;
}
//
// Indent the GUID.
//
Status = LsapAdtAppendZString(
ResultantString,
FreeWhenDone,
Tabs[IndentLevel],
&ResultantStringIndex );
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
//
// If this is the DS,
// convert the GUID to a name from the schema.
//
Status = LsapDsGuidToString( &ObjectTypeList[Index].ObjectType,
&LocalString );
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
//
// Append the GUID string to the output strings.
//
Status = LsapAdtAppendString(
ResultantString,
FreeWhenDone,
&LocalString,
&ResultantStringIndex );
LsapFreeLsaHeap( LocalString.Buffer );
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
//
// Put the GUID on a line by itself.
//
Status = LsapAdtAppendZString(
ResultantString,
FreeWhenDone,
LSAP_ADT_ACCESS_NAME_FORMATTING_NL,
&ResultantStringIndex );
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
}
Status = STATUS_SUCCESS;
Cleanup:
return Status;
}
NTSTATUS
LsapAdtBuildAccessesString(
IN PUNICODE_STRING SourceModule,
IN PUNICODE_STRING ObjectTypeName,
IN ACCESS_MASK Accesses,
IN BOOLEAN Indent,
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone
)
/*++
Routine Description:
This function builds a unicode string containing parameter
file replacement parameters (e.g. %%1043) separated by carriage
return and tab characters suitable for display via the event viewer.
The buffer returned by this routine must be deallocated when no
longer needed if FreeWhenDone is true.
NOTE: To enhance performance, each time a target source module
descriptor is found, it is moved to the beginning of the
source module list. This ensures frequently accessed source
modules are always near the front of the list.
Similarly, target object descriptors are moved to the front
of their lists when found. This further ensures high performance
by quicly locating
Arguments:
SourceModule - The module (ala event viewer modules) defining the
object type.
ObjectTypeName - The type of object to which the access mask applies.
Accesses - The access mask to be used in building the display string.
Indent - Access Mask should be indented.
ResultantString - Points to the unicode string header. The body of this
unicode string will be set to point to the resultant output value
if successful. Otherwise, the Buffer field of this parameter
will be set to NULL.
FreeWhenDone - If TRUE, indicates that the body of the ResultantString
must be freed to process heap when no longer needed.
Return Values:
STATUS_NO_MEMORY - indicates memory could not be allocated
to store the object information.
All other Result Codes are generated by called routines.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG AccessCount = 0;
ULONG BaseOffset;
ULONG i;
ACCESS_MASK Mask;
PLSAP_ADT_SOURCE Source;
PLSAP_ADT_SOURCE FoundSource = NULL;
PLSAP_ADT_OBJECT Object;
PLSAP_ADT_OBJECT FoundObject = NULL;
BOOLEAN Found;
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("Module:\t%wS\n", SourceModule);
printf("\t Object:\t%wS\n", ObjectTypeName);
printf("\t Accesses:\t0x%lx\n", Accesses);
#endif
//
// If we have no accesses, return "-"
//
if (Accesses == 0) {
RtlInitUnicodeString( ResultantString, L"-" );
(*FreeWhenDone) = FALSE;
return(STATUS_SUCCESS);
}
//
// First figure out how large a buffer we need
//
Mask = Accesses;
//
// Count the number of set bits in the
// passed access mask.
//
while ( Mask != 0 ) {
Mask = Mask & (Mask - 1);
AccessCount++;
}
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t \t%d bits set in mask.\n", AccessCount);
#endif
//
// We have accesses, allocate a string large enough to deal
// with them all. Strings will be of the format:
//
// %%nnnnnnnnnn\n\r\t\t%%nnnnnnnnnn\n\r\t\t ... %nnnnnnnnnn\n\r\t\t
//
// where nnnnnnnnnn - is a decimal number 10 digits long or less.
//
// So, a typical string will look like:
//
// %%601\n\r\t\t%%1604\n\r\t\t%%1608\n
//
// Since each such access may use at most:
//
// 10 (for the nnnnnnnnnn digit)
// + 2 (for %%)
// + 8 (for \n\t\t)
// --------------------------------
// 20 wide characters
//
// The total length of the output string will be:
//
// AccessCount (number of accesses)
// x 20 (size of each entry)
// -------------------------------------
// wchars
//
// Throw in 1 more WCHAR for null termination, and we are all set.
//
ResultantString->Length = 0;
ResultantString->MaximumLength = (USHORT)AccessCount * (20 * sizeof(WCHAR)) +
sizeof(WCHAR); //for the null termination
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t \t%d byte buffer allocated.\n", ResultantString->MaximumLength);
#endif
ResultantString->Buffer = LsapAllocateLsaHeap( ResultantString->MaximumLength );
if (ResultantString->Buffer == NULL) {
return(STATUS_NO_MEMORY);
}
(*FreeWhenDone) = TRUE;
//
// Special case standard and special access types.
// Walk the lists for specific access types.
//
if (Accesses & STANDARD_RIGHTS_ALL) {
if (Accesses & DELETE) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringDelete);
ASSERT( NT_SUCCESS( Status ));
if ( Indent ) {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
} else {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING_NL );
}
ASSERT( NT_SUCCESS( Status ));
}
if (Accesses & READ_CONTROL) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringReadControl);
ASSERT( NT_SUCCESS( Status ));
if ( Indent ) {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
} else {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING_NL );
}
ASSERT( NT_SUCCESS( Status ));
}
if (Accesses & WRITE_DAC) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringWriteDac);
ASSERT( NT_SUCCESS( Status ));
if ( Indent ) {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
} else {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING_NL );
}
ASSERT( NT_SUCCESS( Status ));
}
if (Accesses & WRITE_OWNER) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringWriteOwner);
ASSERT( NT_SUCCESS( Status ));
if ( Indent ) {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
} else {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING_NL );
}
ASSERT( NT_SUCCESS( Status ));
}
if (Accesses & SYNCHRONIZE) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringSynchronize);
ASSERT( NT_SUCCESS( Status ));
if ( Indent ) {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
} else {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING_NL );
}
ASSERT( NT_SUCCESS( Status ));
}
}
if (Accesses & ACCESS_SYSTEM_SECURITY) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringAccessSysSec);
ASSERT( NT_SUCCESS( Status ));
if ( Indent ) {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
} else {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING_NL );
}
ASSERT( NT_SUCCESS( Status ));
}
if (Accesses & MAXIMUM_ALLOWED) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &LsapAdtEventIdStringMaxAllowed);
ASSERT( NT_SUCCESS( Status ));
if ( Indent ) {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
} else {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING_NL );
}
ASSERT( NT_SUCCESS( Status ));
}
//
// If there are any specific access bits set, then get
// the appropriate source module and object type base
// message ID offset. If there is no module-specific
// object definition, then use SE_ACCESS_NAME_SPECIFIC_0
// as the base.
//
if ((Accesses & SPECIFIC_RIGHTS_ALL) == 0) {
return(Status);
}
LsapAdtSourceModuleLock();
Source = (PLSAP_ADT_SOURCE)&LsapAdtSourceModules;
Found = FALSE;
while ((Source->Next != NULL) && !Found) {
if (RtlEqualUnicodeString(&Source->Next->Name, SourceModule, TRUE)) {
Found = TRUE;
FoundSource = Source->Next;
//
// Move to front of list of source modules.
//
Source->Next = FoundSource->Next; // Remove from list
FoundSource->Next = LsapAdtSourceModules; // point to first element
LsapAdtSourceModules = FoundSource; // Make it the first element
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t \tModule Found.\n");
#endif
} else {
Source = Source->Next;
}
}
if (Found == TRUE) {
//
// Find the object
//
Object = (PLSAP_ADT_OBJECT)&(FoundSource->Objects);
Found = FALSE;
while ((Object->Next != NULL) && !Found) {
if (RtlEqualUnicodeString(&Object->Next->Name, ObjectTypeName, TRUE)) {
Found = TRUE;
FoundObject = Object->Next;
//
// Move to front of list of soure modules.
//
Object->Next = FoundObject->Next; // Remove from list
FoundObject->Next = FoundSource->Objects; // point to first element
FoundSource->Objects = FoundObject; // Make it the first element
} else {
Object = Object->Next;
}
}
}
//
// We are done playing with link fields of the source modules
// and objects. Free the lock.
//
LsapAdtSourceModuleUnlock();
//
// If we have found an object, use it as our base message
// ID. Otherwise, use SE_ACCESS_NAME_SPECIFIC_0.
//
if (Found) {
BaseOffset = FoundObject->BaseOffset;
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t \tObject Found. Base Offset: 0x%lx\n", BaseOffset);
#endif
} else {
BaseOffset = SE_ACCESS_NAME_SPECIFIC_0;
#ifdef LSAP_ADT_TEST_DUMP_SOURCES
printf("\t \tObject NOT Found. Base Offset: 0x%lx\n", BaseOffset);
#endif
}
//
// At this point, we have a base offset (even if we had to use our
// default).
//
// Now cycle through the specific access bits and see which ones need
// to be added to ResultantString.
//
{
UNICODE_STRING IntegerString;
WCHAR IntegerStringBuffer[10]; //must be 10 wchar bytes long
ULONG NextBit;
IntegerString.Buffer = (PWSTR)IntegerStringBuffer;
IntegerString.MaximumLength = 10*sizeof(WCHAR);
IntegerString.Length = 0;
for ( i=0, NextBit=1 ; i<16 ; i++, NextBit <<= 1 ) {
//
// specific access flags are in the low-order bits of the mask
//
if ((NextBit & Accesses) != 0) {
//
// Found one - add it to ResultantString
//
Status = RtlIntegerToUnicodeString (
(BaseOffset + i),
10, //Base
&IntegerString
);
if (NT_SUCCESS(Status)) {
Status = RtlAppendUnicodeToString( ResultantString, L"%%" );
ASSERT( NT_SUCCESS( Status ));
Status = RtlAppendUnicodeStringToString( ResultantString, &IntegerString);
ASSERT( NT_SUCCESS( Status ));
if ( Indent ) {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING );
} else {
Status = RtlAppendUnicodeToString( ResultantString, LSAP_ADT_ACCESS_NAME_FORMATTING_NL );
}
ASSERT( NT_SUCCESS( Status ));
}
}
}
}
return(Status);
//ErrorAfterAlloc:
//
// LsapFreeLsaHeap( ResultantString->Buffer );
// ResultantString->Buffer = NULL;
// (*FreeWhenDone) = FALSE;
// return(Status);
}
// ======================================================================
// dbpriv.c
// ======================================================================
NTSTATUS
LsapBuildPrivilegeAuditString(
IN PPRIVILEGE_SET PrivilegeSet,
OUT PUNICODE_STRING ResultantString,
OUT PBOOLEAN FreeWhenDone
)
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING DashString;
BOOLEAN FreeDash;
Status= LsapAdtBuildDashString(
&DashString,
&FreeDash
);
if ( !NT_SUCCESS( Status )) {
return( Status );
}
*ResultantString = DashString;
*FreeWhenDone = FALSE;
return Status;
}
NTSTATUS
LsapAdtWriteLog(
IN PSE_ADT_PARAMETER_ARRAY AuditParameters OPTIONAL,
IN ULONG Options
)
{
return LsapAdtDemarshallAuditInfo( AuditParameters );
}
BOOLEAN
LsapAdtIsAuditingEnabledForCategory(
IN POLICY_AUDIT_EVENT_TYPE AuditCategory,
IN UINT AuditEventType
)
{
return TRUE;
}
VOID
LsapAuditFailed(
IN NTSTATUS AuditStatus
)
{
UNREFERENCED_PARAMETER(AuditStatus);
}
#endif // !defined(lint)