mirror of https://github.com/lianthony/NT4.0
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.
621 lines
16 KiB
621 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1991-1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
LOGCLEAR.C
|
|
|
|
Abstract:
|
|
|
|
Contains functions used to log an event indicating who cleared the log.
|
|
This is only called after the security log has been cleared.
|
|
|
|
Author:
|
|
|
|
Dan Lafferty (danl) 01-July-1994
|
|
|
|
Environment:
|
|
|
|
User Mode -Win32
|
|
|
|
Revision History:
|
|
|
|
01-July-1994 danl & robertre
|
|
Created - Rob supplied the code which I fitted into the eventlog.
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <msaudite.h>
|
|
#include <eventp.h>
|
|
#include <tstr.h>
|
|
|
|
#define NUM_STRINGS 6
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
PUNICODE_STRING pGlobalComputerNameU = NULL;
|
|
PANSI_STRING pGlobalComputerNameA = NULL;
|
|
|
|
//
|
|
// LOCAL FUNCTION PROTOTYPES
|
|
//
|
|
BOOL
|
|
GetUserInfo(
|
|
IN HANDLE Token,
|
|
OUT LPWSTR *UserName,
|
|
OUT LPWSTR *DomainName,
|
|
OUT LPWSTR *AuthenticationId,
|
|
OUT PSID *UserSid
|
|
);
|
|
|
|
NTSTATUS
|
|
ElfpGetComputerName (
|
|
IN LPSTR *ComputerNamePtr
|
|
);
|
|
|
|
PUNICODE_STRING
|
|
TmpGetComputerNameW (VOID);
|
|
|
|
VOID
|
|
w_GetComputerName ( );
|
|
|
|
|
|
VOID
|
|
ElfpGenerateLogClearedEvent(
|
|
IELF_HANDLE LogHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function generates an event indicating that the log was cleared.
|
|
|
|
Arguments:
|
|
|
|
LogHandle - This is a handle to the log that the event is to be placed in.
|
|
It is intended that this function only be called when the SecurityLog
|
|
has been cleared. So it is expected the LogHandle will always be
|
|
a handle to the security log.
|
|
|
|
Return Value:
|
|
|
|
NONE - Either it works or it doesn't. If it doesn't, there isn't much
|
|
we can do about it.
|
|
|
|
--*/
|
|
{
|
|
LPWSTR UserName=NULL;
|
|
LPWSTR DomainName=NULL;
|
|
LPWSTR AuthenticationId=NULL;
|
|
LPWSTR ClientUserName=NULL;
|
|
LPWSTR ClientDomainName=NULL;
|
|
LPWSTR ClientAuthenticationId=NULL;
|
|
PSID UserSid=NULL;
|
|
PSID ClientSid=NULL;
|
|
DWORD i;
|
|
BOOL Result;
|
|
HANDLE Token;
|
|
PUNICODE_STRING StringPtrArray[NUM_STRINGS];
|
|
UNICODE_STRING StringArray[NUM_STRINGS];
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER Time;
|
|
ULONG EventTime;
|
|
PUNICODE_STRING pComputerNameU;
|
|
|
|
Result = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &Token );
|
|
|
|
if (!Result) {
|
|
ElfDbgPrint(("OpenProcessToken failed, error = %d",GetLastError()));
|
|
return;
|
|
}
|
|
|
|
Result = GetUserInfo(
|
|
Token,
|
|
&UserName,
|
|
&DomainName,
|
|
&AuthenticationId,
|
|
&UserSid );
|
|
|
|
CloseHandle( Token );
|
|
|
|
if (!Result) {
|
|
ElfDbgPrint(("1st GetUserInfo ret'd %d\n",GetLastError()));
|
|
return;
|
|
}
|
|
|
|
ElfDbgPrint(("\nGetUserInfo ret'd \nUserName = %ws, "
|
|
"\nDomainName = %ws, \nAuthenticationId = %ws\n",
|
|
UserName, DomainName, AuthenticationId ));
|
|
|
|
Result = OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, FALSE, &Token );
|
|
|
|
if (Result) {
|
|
|
|
Result = GetUserInfo(
|
|
Token,
|
|
&ClientUserName,
|
|
&ClientDomainName,
|
|
&ClientAuthenticationId,
|
|
&ClientSid );
|
|
|
|
CloseHandle( Token );
|
|
|
|
if (!Result) {
|
|
ElfDbgPrint(("2nd GetUserInfo ret'd %d\n",GetLastError()));
|
|
goto CleanExit;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Either got access denied or we're not impersonating.
|
|
// Use dash strings either way.
|
|
//
|
|
|
|
ClientUserName = L"-";
|
|
ClientDomainName = L"-";
|
|
ClientAuthenticationId = L"-";
|
|
}
|
|
|
|
ElfDbgPrint(("\nGetUserInfo ret'd \nUserName = %ws, "
|
|
"\nDomainName = %ws, \nAuthenticationId = %ws\n",
|
|
ClientUserName, ClientDomainName, ClientAuthenticationId ));
|
|
|
|
|
|
RtlInitUnicodeString( &StringArray[0], UserName );
|
|
RtlInitUnicodeString( &StringArray[1], DomainName );
|
|
RtlInitUnicodeString( &StringArray[2], AuthenticationId );
|
|
RtlInitUnicodeString( &StringArray[3], ClientUserName );
|
|
RtlInitUnicodeString( &StringArray[4], ClientDomainName );
|
|
RtlInitUnicodeString( &StringArray[5], ClientAuthenticationId );
|
|
|
|
//
|
|
// Create an array of pointers to UNICODE_STRINGs.
|
|
//
|
|
for (i=0; i<NUM_STRINGS; i++) {
|
|
StringPtrArray[i] = &StringArray[i];
|
|
}
|
|
|
|
//
|
|
// Generate the time of the event. This is done on the client side
|
|
// since that is where the event occurred.
|
|
//
|
|
NtQuerySystemTime(&Time);
|
|
RtlTimeToSecondsSince1970(&Time,
|
|
&EventTime
|
|
);
|
|
//
|
|
// Generate the ComputerName of the client.
|
|
// We have to do this in the client side since this call may be
|
|
// remoted to another server and we would not necessarily have
|
|
// the computer name there.
|
|
//
|
|
pComputerNameU = TmpGetComputerNameW();
|
|
|
|
Status = ElfrReportEventW (
|
|
LogHandle, // Log Handle
|
|
EventTime, // Time
|
|
EVENTLOG_AUDIT_SUCCESS, // Event Type
|
|
(USHORT)SE_CATEGID_SYSTEM, // Event Category
|
|
SE_AUDITID_AUDIT_LOG_CLEARED, // EventID
|
|
NUM_STRINGS, // NumStrings
|
|
0, // DataSize
|
|
pComputerNameU, // pComputerNameU
|
|
UserSid, // UserSid
|
|
StringPtrArray, // *Strings
|
|
NULL, // Data
|
|
0, // Flags
|
|
NULL, // RecordNumber
|
|
NULL // TimeWritten
|
|
);
|
|
|
|
CleanExit:
|
|
//
|
|
// We only come down this path if we know for sure that these
|
|
// first three have been allocated.
|
|
//
|
|
ElfpFreeBuffer(UserName);
|
|
ElfpFreeBuffer(DomainName);
|
|
ElfpFreeBuffer(AuthenticationId);
|
|
|
|
if (UserSid != NULL) {
|
|
ElfpFreeBuffer(UserSid);
|
|
}
|
|
if (ClientUserName != NULL) {
|
|
ElfpFreeBuffer(ClientUserName);
|
|
}
|
|
if (ClientDomainName != NULL) {
|
|
ElfpFreeBuffer(ClientDomainName);
|
|
}
|
|
if (ClientAuthenticationId != NULL) {
|
|
ElfpFreeBuffer(ClientAuthenticationId);
|
|
}
|
|
if (ClientSid != NULL) {
|
|
ElfpFreeBuffer(ClientSid);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
GetUserInfo(
|
|
IN HANDLE Token,
|
|
OUT LPWSTR *UserName,
|
|
OUT LPWSTR *DomainName,
|
|
OUT LPWSTR *AuthenticationId,
|
|
OUT PSID *UserSid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function gathers information about the user identified with the
|
|
token.
|
|
|
|
Arguments:
|
|
Token - This token identifies the entity for which we are gathering
|
|
information.
|
|
UserName - This is the entity's user name.
|
|
DomainName - This is the entity's domain name.
|
|
AuthenticationId - This is the entity's Authentication ID.
|
|
UserSid - This is the entity's SID.
|
|
|
|
NOTE:
|
|
Memory is allocated by this routine for UserName, DomainName,
|
|
AuthenticationId, and UserSid. It is the caller's responsibility to
|
|
free this memory.
|
|
|
|
Return Value:
|
|
TRUE - If the operation was successful. It is possible that
|
|
UserSid did not get allocated in the successful case. Therefore,
|
|
the caller should test prior to freeing.
|
|
FALSE - If unsuccessful. No memory is allocated in this case.
|
|
|
|
|
|
--*/
|
|
{
|
|
PTOKEN_USER Buffer=NULL;
|
|
// WCHAR User[256];
|
|
LPWSTR Domain = NULL;
|
|
LPWSTR AccountName = NULL;
|
|
SID_NAME_USE Use;
|
|
BOOL Result;
|
|
DWORD RequiredLength;
|
|
DWORD AccountNameSize;
|
|
DWORD DomainNameSize;
|
|
TOKEN_STATISTICS Statistics;
|
|
WCHAR LogonIdString[256];
|
|
DWORD Status=ERROR_SUCCESS;
|
|
|
|
|
|
*UserSid = NULL;
|
|
|
|
Result = GetTokenInformation ( Token, TokenUser, NULL, 0, &RequiredLength );
|
|
|
|
if (!Result) {
|
|
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
Buffer = ElfpAllocateBuffer((RequiredLength+1)*sizeof(WCHAR) );
|
|
|
|
Result = GetTokenInformation ( Token,
|
|
TokenUser,
|
|
Buffer,
|
|
RequiredLength,
|
|
&RequiredLength
|
|
);
|
|
|
|
if (!Result) {
|
|
ElfDbgPrint(("2nd GetTokenInformation failed, "
|
|
"error = %d\n",GetLastError()));
|
|
return( FALSE );
|
|
}
|
|
|
|
} else {
|
|
|
|
DbgPrint("1st GetTokenInformation failed, error = %d\n",GetLastError());
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
|
|
if (!Result) {
|
|
goto ErrorCleanup;
|
|
}
|
|
|
|
AccountNameSize = 0;
|
|
DomainNameSize = 0;
|
|
|
|
Result = LookupAccountSidW( L"",
|
|
Buffer->User.Sid,
|
|
NULL,
|
|
&AccountNameSize,
|
|
NULL,
|
|
&DomainNameSize,
|
|
&Use
|
|
);
|
|
|
|
if (!Result) {
|
|
|
|
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
|
|
|
|
AccountName = ElfpAllocateBuffer((AccountNameSize+1)*sizeof(WCHAR) );
|
|
Domain = ElfpAllocateBuffer((DomainNameSize+1)*sizeof(WCHAR) );
|
|
|
|
if ( AccountName == NULL ) {
|
|
ElfDbgPrint(("LocalAlloc failed allocating %d bytes, "
|
|
"error = %d\n",AccountNameSize,GetLastError()));
|
|
goto ErrorCleanup;
|
|
}
|
|
|
|
if ( Domain == NULL ) {
|
|
ElfDbgPrint(("LocalAlloc failed allocating %d bytes, "
|
|
"error = %d\n",DomainNameSize,GetLastError()));
|
|
goto ErrorCleanup;
|
|
}
|
|
|
|
Result = LookupAccountSidW( L"",
|
|
Buffer->User.Sid,
|
|
AccountName,
|
|
&AccountNameSize,
|
|
Domain,
|
|
&DomainNameSize,
|
|
&Use
|
|
);
|
|
if (!Result) {
|
|
|
|
ElfDbgPrint(("2nd LookupAccountSid failed, "
|
|
"error = %d\n",GetLastError()));
|
|
goto ErrorCleanup;
|
|
}
|
|
|
|
} else {
|
|
|
|
ElfDbgPrint(("1st LookupAccountSid failed, "
|
|
"error = %d\n",GetLastError()));
|
|
goto ErrorCleanup;
|
|
}
|
|
|
|
} else {
|
|
|
|
ElfDbgPrint(("LookupAccountSid succeeded unexpectedly\n"));
|
|
goto ErrorCleanup;
|
|
}
|
|
|
|
ElfDbgPrint(("Name = %ws\\%ws\n",Domain,AccountName));
|
|
|
|
Result = GetTokenInformation ( Token, TokenStatistics, &Statistics, sizeof( Statistics ), &RequiredLength );
|
|
|
|
if (!Result) {
|
|
ElfDbgPrint(("GetTokenInformation failed, error = %d\n",GetLastError()));
|
|
goto ErrorCleanup;
|
|
}
|
|
|
|
swprintf(LogonIdString, L"(0x%X,0x%X)",Statistics.AuthenticationId.HighPart, Statistics.AuthenticationId.LowPart );
|
|
ElfDbgPrint(("LogonIdString = %ws\n",LogonIdString));
|
|
|
|
*AuthenticationId = ElfpAllocateBuffer(WCSSIZE(LogonIdString));
|
|
if (*AuthenticationId == NULL) {
|
|
ElfDbgPrint(("[ELF]GetUserInfo: Failed to allocate buffer "
|
|
"for AuthenticationId %d\n",GetLastError()));
|
|
goto ErrorCleanup;
|
|
}
|
|
wcscpy(*AuthenticationId, LogonIdString);
|
|
|
|
//
|
|
// Return accumulated information
|
|
//
|
|
|
|
*UserSid = ElfpAllocateBuffer(GetLengthSid( Buffer->User.Sid ) );
|
|
|
|
Result = CopySid( GetLengthSid( Buffer->User.Sid ), *UserSid, Buffer->User.Sid );
|
|
|
|
ElfpFreeBuffer(Buffer);
|
|
|
|
*DomainName = Domain;
|
|
*UserName = AccountName;
|
|
|
|
return( TRUE );
|
|
|
|
ErrorCleanup:
|
|
|
|
if (Buffer != NULL) {
|
|
ElfpFreeBuffer( Buffer );
|
|
}
|
|
|
|
if (Domain != NULL) {
|
|
ElfpFreeBuffer( Domain );
|
|
}
|
|
|
|
if (AccountName != NULL) {
|
|
ElfpFreeBuffer( AccountName );
|
|
}
|
|
|
|
if (*UserSid != NULL) {
|
|
ElfpFreeBuffer( *UserSid );
|
|
}
|
|
|
|
if (*AuthenticationId != NULL) {
|
|
ElfpFreeBuffer( *AuthenticationId );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
NTSTATUS
|
|
ElfpGetComputerName (
|
|
IN LPSTR *ComputerNamePtr)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine obtains the computer name from a persistent database,
|
|
by calling the GetcomputerNameA Win32 Base API
|
|
|
|
This routine assumes the length of the computername is no greater
|
|
than MAX_COMPUTERNAME_LENGTH, space for which it allocates using
|
|
LocalAlloc. It is necessary for the user to free that space using
|
|
ElfpFreeBuffer when finished.
|
|
|
|
Arguments:
|
|
|
|
ComputerNamePtr - This is a pointer to the location where the pointer
|
|
to the computer name is to be placed.
|
|
|
|
Return Value:
|
|
|
|
NERR_Success - If the operation was successful.
|
|
|
|
It will return assorted Net or Win32 or NT error messages if not.
|
|
|
|
--*/
|
|
{
|
|
DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
|
|
|
|
//
|
|
// Allocate a buffer to hold the largest possible computer name.
|
|
//
|
|
|
|
*ComputerNamePtr = ElfpAllocateBuffer(nSize);
|
|
|
|
if (*ComputerNamePtr == NULL) {
|
|
return (GetLastError());
|
|
}
|
|
|
|
//
|
|
// Get the computer name string into the locally allocated buffer
|
|
// by calling the Win32 GetComputerNameA API.
|
|
//
|
|
|
|
if (!GetComputerNameA(*ComputerNamePtr, &nSize)) {
|
|
ElfpFreeBuffer(*ComputerNamePtr);
|
|
*ComputerNamePtr = NULL;
|
|
return (GetLastError());
|
|
}
|
|
|
|
return (ERROR_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
w_GetComputerName ( )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the name of the computer. It checks the global
|
|
variable to see if the computer name has already been determined.
|
|
If not, it updates that variable with the name.
|
|
It does this for the UNICODE and the ANSI versions.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
|
|
--*/
|
|
{
|
|
PUNICODE_STRING pNameU=NULL;
|
|
PANSI_STRING pNameA=NULL;
|
|
LPSTR pName;
|
|
NTSTATUS Error;
|
|
NTSTATUS Status;
|
|
|
|
|
|
if (pGlobalComputerNameU != NULL) {
|
|
return;
|
|
}
|
|
pNameU = ElfpAllocateBuffer (sizeof (UNICODE_STRING));
|
|
pNameA = ElfpAllocateBuffer (sizeof (ANSI_STRING));
|
|
|
|
if ((pNameU != NULL) && (pNameA != NULL)) {
|
|
|
|
if ((Error = ElfpGetComputerName (&pName)) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// ElfpComputerName has allocated a buffer to contain the
|
|
// ASCII name of the computer. We use that for the ANSI
|
|
// string structure.
|
|
//
|
|
RtlInitAnsiString ( pNameA, pName );
|
|
|
|
} else {
|
|
//
|
|
// We could not get the computer name for some reason. Set up
|
|
// the golbal pointer to point to the NULL string.
|
|
//
|
|
RtlInitAnsiString ( pNameA, "\0");
|
|
}
|
|
|
|
//
|
|
// Set up the UNICODE_STRING structure.
|
|
//
|
|
Status = RtlAnsiStringToUnicodeString (
|
|
pNameU,
|
|
pNameA,
|
|
TRUE
|
|
);
|
|
|
|
//
|
|
// If there was no error, set the global variables.
|
|
// Otherwise, free the buffer allocated by ElfpGetComputerName
|
|
// and leave the global variables unchanged.
|
|
//
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
pGlobalComputerNameU = pNameU; // Set global variable if no error
|
|
pGlobalComputerNameA = pNameA; // Set global ANSI variable
|
|
|
|
} else {
|
|
|
|
ElfDbgPrint(("[ELFCLNT] GetComputerName - Error 0x%lx\n", Status));
|
|
ElfpFreeBuffer(pName);
|
|
ElfpFreeBuffer (pNameU); // Free the buffers
|
|
ElfpFreeBuffer (pNameA);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
PUNICODE_STRING
|
|
TmpGetComputerNameW ( )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the UNICODE name of the computer. It checks the global
|
|
variable to see if the computer name has already been determined.
|
|
If not, it calls the worker routine to do that.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the computer name, or a NULL.
|
|
|
|
|
|
--*/
|
|
{
|
|
if (pGlobalComputerNameU == NULL) {
|
|
w_GetComputerName();
|
|
}
|
|
return (pGlobalComputerNameU);
|
|
}
|
|
|
|
|
|
|