|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
slmcheck.c
Abstract:
This source file defines a single function that will check the consistency of a SLM Status file.
--*/
#include "precomp.h"
#include "slmcheck.tmh"
#pragma hdrstop
#ifdef SLMDBG
//
// This is terrible
//
NTSTATUS NtCreateEvent ( OUT PHANDLE EventHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN EVENT_TYPE EventType, IN BOOLEAN InitialState );
//
// So is this
//
NTSTATUS NtWaitForSingleObject( IN HANDLE Handle, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL );
BOOLEAN SrvDisallowSlmAccessEnabled = FALSE; BOOLEAN SrvSlmFailed = FALSE;
#define toupper(c) ( (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c )
NTSTATUS SrvpValidateStatusFile( IN PVOID StatusFileData, IN ULONG StatusFileLength, OUT PULONG FileOffsetOfInvalidData );
VOID SrvReportCorruptSlmStatus ( IN PUNICODE_STRING StatusFile, IN NTSTATUS Status, IN ULONG Offset, IN ULONG Operation, IN PSESSION Session ) { NTSTATUS status; ANSI_STRING ansiStatusFile; TIME time; TIME_FIELDS timeFields; ULONG i, j; UNICODE_STRING userName;
if( SrvSlmFailed ) { return; }
status = RtlUnicodeStringToAnsiString( &ansiStatusFile, StatusFile, TRUE ); ASSERT( NT_SUCCESS(status) );
KeQuerySystemTime( &time ); RtlTimeToTimeFields( &time, &timeFields );
SrvGetUserAndDomainName ( Session, &userName, NULL );
KdPrint(( "\n*** CORRUPT STATUS FILE DETECTED ***\n" " File: %Z\n" " Status: 0x%lx, Offset: 0x%lx, detected on %s\n", &ansiStatusFile, Status, Offset, Operation == SLMDBG_CLOSE ? "close" : "rename" )); KdPrint(( " Workstation: %wZ, User: %wZ, OS: %d\n", &Session->Connection->PagedConnection->ClientMachineNameString, &userName, &SrvClientTypes[Session->Connection->SmbDialect] )); KdPrint(( " Current time: %d-%d-%d ", timeFields.Month, timeFields.Day, timeFields.Year )); KdPrint(( "%d:%d:%d\n", timeFields.Hour, timeFields.Minute, timeFields.Second ));
SrvReleaseUserAndDomainName( Session, &userName, NULL );
#if 0
//
// Send a broadcast message.
//
SrvSendSecondClassMailslot( ansiStatusFile.Buffer, StatusFile->Length + 1, "BLUBBER", "BLUBBER" ); #endif
RtlFreeAnsiString( &ansiStatusFile );
} // SrvReportCorruptSlmStatus
VOID SrvReportSlmStatusOperations ( IN PRFCB Rfcb, IN BOOLEAN Force ) { ULONG first, last, i; PRFCB_TRACE trace; TIME_FIELDS timeFields; PSZ command; BOOLEAN oplockBreak;
if( !Force && SrvSlmFailed ) { return; }
KdPrint(( " Number of operations: %d, number of writes: %d\n", Rfcb->OperationCount, Rfcb->WriteCount ));
if( Rfcb->Connection && GET_BLOCK_STATE(Rfcb->Connection) != BlockStateActive ) { KdPrint(( " Connection State = %u\n", GET_BLOCK_STATE( Rfcb->Connection ))); }
if ( Rfcb->TraceWrapped || (Rfcb->NextTrace != 0) ) {
first = Rfcb->TraceWrapped ? Rfcb->NextTrace : 0; last = Rfcb->NextTrace == 0 ? SLMDBG_TRACE_COUNT - 1 : Rfcb->NextTrace - 1;
i = first;
while ( TRUE ) {
trace = &Rfcb->Trace[i];
RtlTimeToTimeFields( &trace->Time, &timeFields ); KdPrint(( " %s%d: ", i < 10 ? "0" : "", i )); KdPrint(( "%d-%d-%d ", timeFields.Month, timeFields.Day, timeFields.Year )); KdPrint(( "%s%d:%s%d:", timeFields.Hour < 10 ? "0" : "", timeFields.Hour, timeFields.Minute < 10 ? "0" : "", timeFields.Minute )); KdPrint(( "%s%d: ", timeFields.Second < 10 ? "0" : "", timeFields.Second ));
oplockBreak = FALSE;
switch ( trace->Command ) {
case SMB_COM_READ: case SMB_COM_WRITE: case SMB_COM_READ_ANDX: case SMB_COM_WRITE_ANDX: case SMB_COM_LOCK_AND_READ: case SMB_COM_WRITE_AND_UNLOCK: case SMB_COM_WRITE_AND_CLOSE: case SMB_COM_READ_RAW: case SMB_COM_WRITE_RAW: case SMB_COM_LOCK_BYTE_RANGE: case SMB_COM_UNLOCK_BYTE_RANGE: case SMB_COM_LOCKING_ANDX:
switch ( trace->Command ) {
case SMB_COM_READ: command = "Read"; break;
case SMB_COM_WRITE: command = "Write"; break;
case SMB_COM_READ_ANDX: command = "Read And X"; break;
case SMB_COM_WRITE_ANDX: command = "Write And X"; break;
case SMB_COM_LOCK_AND_READ: command = "Lock And Read"; break;
case SMB_COM_WRITE_AND_UNLOCK: command = "Write And Unlock"; break;
case SMB_COM_WRITE_AND_CLOSE: command = "Write And Close"; break;
case SMB_COM_READ_RAW: if ( (trace->Flags & 1) == 0 ) { command = "Read Raw (copy)"; } else { command = "Read Raw (MDL)"; } break;
case SMB_COM_WRITE_RAW: if ( (trace->Flags & 2) == 0 ) { if ( (trace->Flags & 1) == 0 ) { command = "Write Raw (copy, no immed)"; } else { command = "Write Raw (MDL, no immed)"; } } else { if ( (trace->Flags & 1) == 0 ) { command = "Write Raw (copy, immed)"; } else { command = "Write Raw (MDL, immed)"; } } break;
case SMB_COM_LOCK_BYTE_RANGE: command = "Lock Byte Range"; break;
case SMB_COM_UNLOCK_BYTE_RANGE: command = "Unlock Byte Range"; break;
case SMB_COM_LOCKING_ANDX: if ( trace->Flags == 0 ) { command = "Locking And X (lock)"; } else if ( trace->Flags == 1 ) { command = "Locking And X (unlock)"; } else { command = "Locking And X (release oplock)"; oplockBreak = TRUE; } break;
}
if ( !oplockBreak ) { KdPrint(( "%s, offset = 0x%lx, len = 0x%lx\n", command, trace->Data.ReadWrite.Offset, trace->Data.ReadWrite.Length )); } else { KdPrint(( "%s\n", command )); }
break;
default: KdPrint(( "command = 0x%lx, flags = 0x%lx\n", trace->Command, trace->Flags ));
}
if ( i == last ) break;
if ( ++i == SLMDBG_TRACE_COUNT ) i = 0;
}
}
SrvSendSecondClassMailslot( "SLM CORRUPTION", 15, "BLUBBER", "BLUBBER" );
return;
} // SrvReportSlmStatusOperations
VOID SrvCreateMagicSlmName ( IN PUNICODE_STRING StatusFile, OUT PUNICODE_STRING MagicFile ) { LONG fileLength; ULONG dirLength; PCHAR magicName = "\\status.nfw"; PCHAR src; PWCH dest;
fileLength = (strlen( magicName ) + 1) * sizeof(WCHAR); dirLength = SrvGetSubdirectoryLength( StatusFile ); MagicFile->MaximumLength = (USHORT)(dirLength + fileLength); MagicFile->Length = (USHORT)(MagicFile->MaximumLength - sizeof(WCHAR)); MagicFile->Buffer = ExAllocatePool( PagedPool, MagicFile->MaximumLength ); ASSERT( MagicFile->Buffer != NULL );
RtlCopyMemory( MagicFile->Buffer, StatusFile->Buffer, dirLength ); src = magicName; dest = (PWCH)((PCHAR)MagicFile->Buffer + dirLength); for ( fileLength = strlen(magicName); fileLength >= 0; fileLength-- ) { *dest++ = *src++; }
return;
} // SrvCreateMagicSlmName
VOID SrvDisallowSlmAccess ( IN PUNICODE_STRING StatusFile, IN HANDLE RootDirectory ) { NTSTATUS status; UNICODE_STRING file; OBJECT_ATTRIBUTES objectAttributes; HANDLE fileHandle; IO_STATUS_BLOCK iosb;
if( SrvSlmFailed ) { return; }
SrvSlmFailed = TRUE;
if( SrvDisallowSlmAccessEnabled == FALSE ) { return; }
SrvCreateMagicSlmName( StatusFile, &file );
InitializeObjectAttributes( &objectAttributes, &file, OBJ_CASE_INSENSITIVE, RootDirectory, NULL );
KdPrint(( "Disallowing access to SLM directory %wZ\n", &file ));
status = IoCreateFile( &fileHandle, GENERIC_READ, &objectAttributes, &iosb, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE, NULL, 0, CreateFileTypeNone, NULL, 0 );
ExFreePool( file.Buffer );
if ( NT_SUCCESS(status) ) { status = iosb.Status; } if ( NT_SUCCESS(status) ) { NtClose( fileHandle ); } else { KdPrint(( "Attempt to disallow SLM access failed: 0x%lx\n", status )); }
return;
} // SrvDisallowSlmAccess
BOOLEAN SrvIsSlmAccessDisallowed ( IN PUNICODE_STRING StatusFile, IN HANDLE RootDirectory ) { NTSTATUS status; UNICODE_STRING file; OBJECT_ATTRIBUTES objectAttributes; HANDLE fileHandle; IO_STATUS_BLOCK iosb;
if ( !SrvDisallowSlmAccessEnabled ) { return FALSE; }
SrvCreateMagicSlmName( StatusFile, &file );
InitializeObjectAttributes( &objectAttributes, &file, OBJ_CASE_INSENSITIVE, RootDirectory, NULL );
status = IoCreateFile( &fileHandle, GENERIC_READ, &objectAttributes, &iosb, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0, CreateFileTypeNone, NULL, 0 );
ExFreePool( file.Buffer );
if ( NT_SUCCESS(status) ) { status = iosb.Status; } if ( NT_SUCCESS(status) ) { NtClose( fileHandle ); return TRUE; } else { return FALSE; }
} // SrvIsSlmAccessDisallowed
BOOLEAN SrvIsEtcFile ( IN PUNICODE_STRING FileName ) { if ( ((RtlUnicodeStringToAnsiSize( FileName ) - 1) >= 4) && (toupper(FileName->Buffer[0]) == 'E') && (toupper(FileName->Buffer[1]) == 'T') && (toupper(FileName->Buffer[2]) == 'C') && ( FileName->Buffer[3] == '\\') ) {
return TRUE;
} else {
LONG i;
for ( i = 0; i < (LONG)RtlUnicodeStringToAnsiSize( FileName ) - 1 - 4; i++ ) {
if ( ( FileName->Buffer[i] == '\\') && (toupper(FileName->Buffer[i+1]) == 'E' ) && (toupper(FileName->Buffer[i+2]) == 'T' ) && (toupper(FileName->Buffer[i+3]) == 'C' ) && ( FileName->Buffer[i+4] == '\\') ) {
return TRUE;
}
}
}
return FALSE;
} // SrvIsEtcFile
BOOLEAN SrvIsSlmStatus ( IN PUNICODE_STRING StatusFile ) { UNICODE_STRING baseName;
if ( !SrvIsEtcFile( StatusFile ) ) { return FALSE; }
SrvGetBaseFileName( StatusFile, &baseName );
if ( ((RtlUnicodeStringToAnsiSize( &baseName ) - 1) == 10) && (toupper(baseName.Buffer[0]) == 'S') && (toupper(baseName.Buffer[1]) == 'T') && (toupper(baseName.Buffer[2]) == 'A') && (toupper(baseName.Buffer[3]) == 'T') && (toupper(baseName.Buffer[4]) == 'U') && (toupper(baseName.Buffer[5]) == 'S') && ( baseName.Buffer[6] == '.') && (toupper(baseName.Buffer[7]) == 'S') && (toupper(baseName.Buffer[8]) == 'L') && (toupper(baseName.Buffer[9]) == 'M') ) { return TRUE; }
return FALSE;
} // SrvIsSlmStatus
BOOLEAN SrvIsTempSlmStatus ( IN PUNICODE_STRING StatusFile ) { UNICODE_STRING baseName;
if ( !SrvIsEtcFile( StatusFile ) ) { return FALSE; }
SrvGetBaseFileName( StatusFile, &baseName );
if ( ((RtlUnicodeStringToAnsiSize( &baseName ) - 1) == 5) && (toupper(baseName.Buffer[0]) == 'T') && ( baseName.Buffer[1] == '0') ) { return TRUE; }
return FALSE;
} // SrvIsTempSlmStatus
NTSTATUS SrvValidateSlmStatus( IN HANDLE StatusFile, IN PWORK_CONTEXT WorkContext, OUT PULONG FileOffsetOfInvalidData ) { NTSTATUS Status; IO_STATUS_BLOCK IoStatus; PULONG buffer, p, ep, s; LARGE_INTEGER offset; ULONG previousRun = 0; HANDLE eventHandle; OBJECT_ATTRIBUTES obja; ULONG key;
#define ZERORUNLEN 2048
#define SLMREADSIZE (10 * 4096)
if( SrvSlmFailed ) { return STATUS_SUCCESS; }
buffer = ExAllocatePoolWithTag( NonPagedPool, SLMREADSIZE, BlockTypeDataBuffer ); if( buffer == NULL ) { return STATUS_SUCCESS; }
*FileOffsetOfInvalidData = 0; offset.QuadPart = 0;
InitializeObjectAttributes( &obja, NULL, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtCreateEvent( &eventHandle, EVENT_ALL_ACCESS, &obja, SynchronizationEvent, FALSE );
if( !NT_SUCCESS( Status ) ) { return STATUS_SUCCESS; }
if( ARGUMENT_PRESENT( WorkContext ) ) { key = WorkContext->Rfcb->ShiftedFid | SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid ); }
//
// Scan through the file, looking for a run of zeros
//
while( 1 ) {
RtlZeroMemory( &IoStatus, sizeof( IoStatus ) );
Status = NtReadFile( StatusFile, eventHandle, NULL, NULL, &IoStatus, buffer, SLMREADSIZE, &offset, ARGUMENT_PRESENT( WorkContext ) ? &key : NULL );
if( Status == STATUS_PENDING ) { NtWaitForSingleObject( eventHandle, FALSE, NULL ); }
Status = IoStatus.Status;
if( Status == STATUS_END_OF_FILE ) { break; }
if( Status != STATUS_SUCCESS ) { NtClose( eventHandle ); ExFreePool( buffer ); return Status; } if( IoStatus.Information == 0 ) { break; }
ep = (PULONG)((ULONG)buffer + IoStatus.Information);
for( p = buffer; p < ep; p++ ) { if( *p == 0 ) { for( s = p; s < ep && *s == 0; s++ ) ;
if( (ULONG)s - (ULONG)p >= ZERORUNLEN ) {
*FileOffsetOfInvalidData = offset.LowPart + ((ULONG)p - (ULONG)buffer);
KdPrint(( "SRV: Run of %u zeros in SLM file at offset %u decimal!\n", (ULONG)s - (ULONG)p, *FileOffsetOfInvalidData ));
ExFreePool( buffer ); NtClose( eventHandle ); return STATUS_UNSUCCESSFUL; }
p = s;
} }
offset.QuadPart += IoStatus.Information; }
NtClose( eventHandle ); ExFreePool( buffer );
return( STATUS_SUCCESS ); }
#endif
|