#include "brian.h" #define OPLOCK_VERBOSES_DEFAULT TRUE typedef struct _OPLOCK { ULONG FileHandleIndex; BOOLEAN VerboseResults; USHORT BufferIndex; } OPLOCK, *POPLOCK; // // Local procedures // VOID RequestOplockI ( IN POPLOCK Oplock ); VOID RequestBatchOplock ( IN POPLOCK Oplock ); VOID RequestFilterOplock ( IN POPLOCK Oplock ); VOID RequestOplockII ( IN POPLOCK Oplock ); VOID AcknowledgeOplockBreak ( IN POPLOCK Oplock ); VOID AcknowledgeOplockBreakNo2 ( IN POPLOCK Oplock ); VOID AcknowledgeOpBatchBreakPending ( IN POPLOCK Oplock ); VOID OplockBreakNotify ( IN POPLOCK Oplock ); VOID InputOplock( IN PCHAR ParamBuffer ) { ULONG Operation; BOOLEAN VerboseResults; BOOLEAN DisplayParms; BOOLEAN ParamReceived; BOOLEAN LastInput; POPLOCK Oplock; ULONG FileHandleIndex; VerboseResults = OPLOCK_VERBOSES_DEFAULT; DisplayParms = FALSE; ParamReceived = FALSE; LastInput = TRUE; FileHandleIndex = 0; Operation = (ULONG) -1; // // While there is more input, analyze the parameter and update the // query flags. // while (TRUE) { ULONG DummyCount; // // Swallow leading white spaces. // ParamBuffer = SwallowWhite( ParamBuffer, &DummyCount ); if (*ParamBuffer) { // // If the next parameter is legal then check the paramter value. // Update the parameter value. // if ((*ParamBuffer == '-' || *ParamBuffer == '/') && (ParamBuffer++, *ParamBuffer != '\0')) { BOOLEAN SwitchBool; // // Switch on the next character. // switch (*ParamBuffer) { // // Modify the operation // case 'o' : case 'O' : ParamBuffer++; SwitchBool = TRUE; while (*ParamBuffer && *ParamBuffer != ' ' && *ParamBuffer != '\t') { // // Perform switch on character. // switch (*ParamBuffer) { case 'a' : case 'A' : Operation = FSCTL_REQUEST_OPLOCK_LEVEL_1; ParamReceived = TRUE; break; case 'b' : case 'B' : Operation = FSCTL_REQUEST_OPLOCK_LEVEL_2; ParamReceived = TRUE; break; case 'c' : case 'C' : Operation = FSCTL_REQUEST_BATCH_OPLOCK; ParamReceived = TRUE; break; case 'd' : case 'D' : Operation = FSCTL_REQUEST_FILTER_OPLOCK; ParamReceived = TRUE; break; case 'e' : case 'E' : Operation = FSCTL_OPLOCK_BREAK_ACKNOWLEDGE; ParamReceived = TRUE; break; case 'f' : case 'F' : Operation = FSCTL_OPBATCH_ACK_CLOSE_PENDING; ParamReceived = TRUE; break; case 'g' : case 'G' : Operation = FSCTL_OPLOCK_BREAK_NOTIFY; ParamReceived = TRUE; break; case 'h' : case 'H' : Operation = FSCTL_OPLOCK_BREAK_ACK_NO_2; ParamReceived = TRUE; break; case 'z' : case 'Z' : ParamReceived = FALSE; Operation = (ULONG) -1; break; default : ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount ); SwitchBool = FALSE; } if (!SwitchBool) { break; } ParamBuffer++; } break; // // Update the file handle index. // case 'i' : case 'I' : // // Move to the next character, as long as there // are no white spaces continue analyzing letters. // On the first bad letter, skip to the next // parameter. // ParamBuffer++; FileHandleIndex = AsciiToInteger( ParamBuffer ); ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount ); break; case 'v' : case 'V' : // // Legal values for params are T/t or F/f. // ParamBuffer++; if (*ParamBuffer == 'T' || *ParamBuffer == 't') { VerboseResults = TRUE; ParamBuffer++; } else if (*ParamBuffer == 'F' || *ParamBuffer == 'f') { VerboseResults = FALSE; ParamBuffer++; } ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount ); break; case 'y' : case 'Y' : // // Set the display parms flag and jump over this // character. // DisplayParms = TRUE; ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount ); break; case 'z' : case 'Z' : // // Set flag for more input and jump over this char. // LastInput = FALSE; ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount ); break; default : // // Swallow to the next white space and continue the // loop. // ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount ); } } // // Else the text is invalid, skip the entire block. // // // // Else if there is no input then exit. // } else if (LastInput) { break; // // Else try to read another line for open parameters. // } else { } } // // If no parameters were received then display the syntax message. // if (!ParamReceived) { printf( "\n Usage: oplk -i -o [options]*\n" ); printf( "\n Options:" ); printf( "\n -i Open file handle" ); printf( "\n -o Oplock operation" ); printf( "\n -v[t|f] Verbose results" ); printf( "\n -y Display parameters to query" ); printf( "\n -z Additional input line" ); printf( "\n\n" ); // // Else process the call. // } else { NTSTATUS Status; SIZE_T RegionSize; ULONG TempIndex; USHORT BufferIndex; HANDLE ThreadHandle; ULONG ThreadId; RegionSize = sizeof( OPLOCK ); Status = AllocateBuffer( 0, &RegionSize, &TempIndex ); BufferIndex = (USHORT) TempIndex; if (!NT_SUCCESS( Status )) { printf("\n\tInputOplock: Unable to allocate async structure" ); } else { Oplock = (POPLOCK) Buffers[BufferIndex].Buffer; Oplock->FileHandleIndex = FileHandleIndex; Oplock->VerboseResults = VerboseResults; Oplock->BufferIndex = BufferIndex; if (DisplayParms) { printf( "\nOplock Operation Parameters" ); printf( "\n Handle index -> %ld", FileHandleIndex ); printf( "\n Oplock operation -> %ld", Operation ); printf( "\n Structure buffer index -> %d", BufferIndex ); printf( "\n\n" ); } switch (Operation) { case FSCTL_REQUEST_OPLOCK_LEVEL_1 : ThreadHandle = CreateThread( NULL, 0, RequestOplockI, Oplock, 0, &ThreadId ); break; case FSCTL_REQUEST_OPLOCK_LEVEL_2 : ThreadHandle = CreateThread( NULL, 0, RequestOplockII, Oplock, 0, &ThreadId ); break; case FSCTL_REQUEST_BATCH_OPLOCK : ThreadHandle = CreateThread( NULL, 0, RequestBatchOplock, Oplock, 0, &ThreadId ); break; case FSCTL_REQUEST_FILTER_OPLOCK : ThreadHandle = CreateThread( NULL, 0, RequestFilterOplock, Oplock, 0, &ThreadId ); break; case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE : ThreadHandle = CreateThread( NULL, 0, AcknowledgeOplockBreak, Oplock, 0, &ThreadId ); break; case FSCTL_OPBATCH_ACK_CLOSE_PENDING : ThreadHandle = CreateThread( NULL, 0, AcknowledgeOpBatchBreakPending, Oplock, 0, &ThreadId ); break; case FSCTL_OPLOCK_BREAK_NOTIFY : ThreadHandle = CreateThread( NULL, 0, OplockBreakNotify, Oplock, 0, &ThreadId ); break; case FSCTL_OPLOCK_BREAK_ACK_NO_2 : ThreadHandle = CreateThread( NULL, 0, AcknowledgeOplockBreakNo2, Oplock, 0, &ThreadId ); break; default : printf( "\nInputOplock: Invalid operation\n" ); return; } if (ThreadHandle == 0) { printf( "\nInputOplock: Spawning thread fails -> %d\n", GetLastError() ); } } } return; } VOID RequestOplockI ( IN POPLOCK Oplock ) { HANDLE Event; NTSTATUS Status; IO_STATUS_BLOCK IoSb; IoSb.Status = 0; IoSb.Information = 0; Status = NtCreateEvent( &Event, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, NULL, NotificationEvent, FALSE ); if (!NT_SUCCESS( Status )) { bprint "\nRequestOplockI: NtCreateEvent failed -> %08lx\n", Status ); } else { Status = NtFsControlFile( Handles[Oplock->FileHandleIndex].Handle, Event, NULL, NULL, &IoSb, FSCTL_REQUEST_OPLOCK_LEVEL_1, NULL, 0, NULL, 0 ); if (Oplock->VerboseResults) { bprint "\nRequestOplockI: Status -> %08lx\n", Status ); if (NT_SUCCESS( Status )) { if ((Status = NtWaitForSingleObject( Event, FALSE, NULL )) != STATUS_SUCCESS) { bprint "\n\tRequestOplockI: Wait for event failed -> %08lx", Status ); } } if (NT_SUCCESS( Status )) { bprint "\nRequestOplockI: IoSb.Status -> %08lx", IoSb.Status ); bprint "\nRequestOplockI: IoSb.Information -> %08lx", IoSb.Information ); } bprint "\n" ); } } DeallocateBuffer( Oplock->BufferIndex ); NtTerminateThread( NtCurrentThread(), STATUS_SUCCESS ); bprint "\nRequestOplockI: Thread not terminated\n" ); } VOID RequestBatchOplock ( IN POPLOCK Oplock ) { HANDLE Event; NTSTATUS Status; IO_STATUS_BLOCK IoSb; IoSb.Status = 0; IoSb.Information = 0; Status = NtCreateEvent( &Event, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, NULL, NotificationEvent, FALSE ); if (!NT_SUCCESS( Status )) { bprint "\nRequestBatchOplock: NtCreateEvent failed -> %08lx\n", Status ); } else { Status = NtFsControlFile( Handles[Oplock->FileHandleIndex].Handle, Event, NULL, NULL, &IoSb, FSCTL_REQUEST_BATCH_OPLOCK, NULL, 0, NULL, 0 ); if (Oplock->VerboseResults) { bprint "\nRequestBatchOplock: Status -> %08lx\n", Status ); if (NT_SUCCESS( Status )) { if ((Status = NtWaitForSingleObject( Event, FALSE, NULL )) != STATUS_SUCCESS) { bprint "\n\tRequestBatchOplock: Wait for event failed -> %08lx", Status ); } } if (NT_SUCCESS( Status )) { bprint "\nRequestBatchOplock: IoSb.Status -> %08lx", IoSb.Status ); bprint "\nRequestBatchOplock: IoSb.Information -> %08lx", IoSb.Information ); } bprint "\n" ); } } DeallocateBuffer( Oplock->BufferIndex ); NtTerminateThread( NtCurrentThread(), STATUS_SUCCESS ); bprint "\nRequestBatchOplock: Thread not terminated\n" ); } VOID RequestFilterOplock ( IN POPLOCK Oplock ) { HANDLE Event; NTSTATUS Status; IO_STATUS_BLOCK IoSb; IoSb.Status = 0; IoSb.Information = 0; Status = NtCreateEvent( &Event, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, NULL, NotificationEvent, FALSE ); if (!NT_SUCCESS( Status )) { bprint "\nRequestFilterOplock: NtCreateEvent failed -> %08lx\n", Status ); } else { Status = NtFsControlFile( Handles[Oplock->FileHandleIndex].Handle, Event, NULL, NULL, &IoSb, FSCTL_REQUEST_FILTER_OPLOCK, NULL, 0, NULL, 0 ); if (Oplock->VerboseResults) { bprint "\nRequestFilterOplock: Status -> %08lx\n", Status ); if (NT_SUCCESS( Status )) { if ((Status = NtWaitForSingleObject( Event, FALSE, NULL )) != STATUS_SUCCESS) { bprint "\n\tRequestFilterOplock: Wait for event failed -> %08lx", Status ); } if (NT_SUCCESS( Status )) { bprint "\nRequestFilterOplock: IoSb.Status -> %08lx", IoSb.Status ); bprint "\nRequestFilterOplock: IoSb.Information -> %08lx", IoSb.Information ); } } bprint "\n" ); } } DeallocateBuffer( Oplock->BufferIndex ); NtTerminateThread( NtCurrentThread(), STATUS_SUCCESS ); bprint "\nRequestFilterOplock: Thread not terminated\n" ); } VOID RequestOplockII ( IN POPLOCK Oplock ) { HANDLE Event; NTSTATUS Status; IO_STATUS_BLOCK IoSb; IoSb.Status = 0; IoSb.Information = 0; Status = NtCreateEvent( &Event, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, NULL, NotificationEvent, FALSE ); if (!NT_SUCCESS( Status )) { bprint "\nRequestOplockII: NtCreateEvent failed -> %08lx\n", Status ); } else { Status = NtFsControlFile( Handles[Oplock->FileHandleIndex].Handle, Event, NULL, NULL, &IoSb, FSCTL_REQUEST_OPLOCK_LEVEL_2, NULL, 0, NULL, 0 ); if (Oplock->VerboseResults) { bprint "\nRequestOplockII: Status -> %08lx\n", Status ); if (NT_SUCCESS( Status )) { if ((Status = NtWaitForSingleObject( Event, FALSE, NULL )) != STATUS_SUCCESS) { bprint "\n\tRequestOplockII: Wait for event failed -> %08lx", Status ); } if (NT_SUCCESS( Status )) { bprint "\nRequestOplockII: IoSb.Status -> %08lx", IoSb.Status ); bprint "\nRequestOplockII: IoSb.Information -> %08lx", IoSb.Information ); } } bprint "\n" ); } } DeallocateBuffer( Oplock->BufferIndex ); NtTerminateThread( NtCurrentThread(), STATUS_SUCCESS ); bprint "\nRequestOplockII: Thread not terminated\n" ); } VOID AcknowledgeOplockBreak ( IN POPLOCK Oplock ) { HANDLE Event; NTSTATUS Status; IO_STATUS_BLOCK IoSb; IoSb.Status = 0; IoSb.Information = 0; Status = NtCreateEvent( &Event, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, NULL, NotificationEvent, FALSE ); if (!NT_SUCCESS( Status )) { bprint "\nAcknowledgeOplockBreak: NtCreateEvent failed -> %08lx\n", Status ); } else { Status = NtFsControlFile( Handles[Oplock->FileHandleIndex].Handle, Event, NULL, NULL, &IoSb, FSCTL_OPLOCK_BREAK_ACKNOWLEDGE, NULL, 0, NULL, 0 ); if (Oplock->VerboseResults) { bprint "\nAcknowledgeOplockBreak: Status -> %08lx\n", Status ); if (NT_SUCCESS( Status )) { if ((Status = NtWaitForSingleObject( Event, FALSE, NULL )) != STATUS_SUCCESS) { bprint "\n\tAcknowledgeOplockBreak: Wait for event failed -> %08lx", Status ); } if (NT_SUCCESS( Status )) { bprint "\nAcknowledgeOplockBreak: IoSb.Status -> %08lx", IoSb.Status ); bprint "\nAcknowledgeOplockBreak: IoSb.Information -> %08lx", IoSb.Information ); } } bprint "\n" ); } } DeallocateBuffer( Oplock->BufferIndex ); NtTerminateThread( NtCurrentThread(), STATUS_SUCCESS ); bprint "\nAcknowledgeOplockBreak: Thread not terminated\n" ); } VOID AcknowledgeOplockBreakNo2 ( IN POPLOCK Oplock ) { HANDLE Event; NTSTATUS Status; IO_STATUS_BLOCK IoSb; IoSb.Status = 0; IoSb.Information = 0; Status = NtCreateEvent( &Event, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, NULL, NotificationEvent, FALSE ); if (!NT_SUCCESS( Status )) { bprint "\nAcknowledgeOplockBreakNo2: NtCreateEvent failed -> %08lx\n", Status ); } else { Status = NtFsControlFile( Handles[Oplock->FileHandleIndex].Handle, Event, NULL, NULL, &IoSb, FSCTL_OPLOCK_BREAK_ACK_NO_2, NULL, 0, NULL, 0 ); if (Oplock->VerboseResults) { bprint "\nAcknowledgeOplockBreakNo2: Status -> %08lx\n", Status ); if (NT_SUCCESS( Status )) { if ((Status = NtWaitForSingleObject( Event, FALSE, NULL )) != STATUS_SUCCESS) { bprint "\n\tAcknowledgeOplockBreakNo2: Wait for event failed -> %08lx", Status ); } if (NT_SUCCESS( Status )) { bprint "\nAcknowledgeOplockBreakNo2: IoSb.Status -> %08lx", IoSb.Status ); bprint "\nAcknowledgeOplockBreakNo2: IoSb.Information -> %08lx", IoSb.Information ); } } bprint "\n" ); } } DeallocateBuffer( Oplock->BufferIndex ); NtTerminateThread( NtCurrentThread(), STATUS_SUCCESS ); bprint "\nAcknowledgeOplockBreak: Thread not terminated\n" ); } VOID AcknowledgeOpBatchBreakPending ( IN POPLOCK Oplock ) { HANDLE Event; NTSTATUS Status; IO_STATUS_BLOCK IoSb; IoSb.Status = 0; IoSb.Information = 0; Status = NtCreateEvent( &Event, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, NULL, NotificationEvent, FALSE ); if (!NT_SUCCESS( Status )) { bprint "\nAcknowledgeOpBatchBreakPending: NtCreateEvent failed -> %08lx\n", Status ); } else { Status = NtFsControlFile( Handles[Oplock->FileHandleIndex].Handle, Event, NULL, NULL, &IoSb, FSCTL_OPBATCH_ACK_CLOSE_PENDING, NULL, 0, NULL, 0 ); if (Oplock->VerboseResults) { bprint "\nAcknowledgeOpBatchBreakPending: Status -> %08lx\n", Status ); if (NT_SUCCESS( Status )) { if ((Status = NtWaitForSingleObject( Event, FALSE, NULL )) != STATUS_SUCCESS) { bprint "\n\tAcknowledgeOpBatchBreakPending: Wait for event failed -> %08lx", Status ); } if (NT_SUCCESS( Status )) { bprint "\nAcknowledgeOpBatchBreakPending: IoSb.Status -> %08lx", IoSb.Status ); bprint "\nAcknowledgeOpBatchBreakPending: IoSb.Information -> %08lx", IoSb.Information ); } } bprint "\n" ); } } DeallocateBuffer( Oplock->BufferIndex ); NtTerminateThread( NtCurrentThread(), STATUS_SUCCESS ); bprint "\nAcknowledgeOpBatchBreakPending: Thread not terminated\n" ); } VOID OplockBreakNotify ( IN POPLOCK Oplock ) { HANDLE Event; NTSTATUS Status; IO_STATUS_BLOCK IoSb; IoSb.Status = 0; IoSb.Information = 0; Status = NtCreateEvent( &Event, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, NULL, NotificationEvent, FALSE ); if (!NT_SUCCESS( Status )) { bprint "\nOplockBreakNotify: NtCreateEvent failed -> %08lx\n", Status ); } else { Status = NtFsControlFile( Handles[Oplock->FileHandleIndex].Handle, Event, NULL, NULL, &IoSb, FSCTL_OPLOCK_BREAK_NOTIFY, NULL, 0, NULL, 0 ); if (Oplock->VerboseResults) { bprint "\nOplockBreakNotify: Status -> %08lx\n", Status ); if (NT_SUCCESS( Status )) { if ((Status = NtWaitForSingleObject( Event, FALSE, NULL )) != STATUS_SUCCESS) { bprint "\n\tOplockBreakNotify: Wait for event failed -> %08lx", Status ); } if (NT_SUCCESS( Status )) { bprint "\nOplockBreakNotify: IoSb.Status -> %08lx", IoSb.Status ); bprint "\nOplockBreakNotify: IoSb.Information -> %08lx", IoSb.Information ); } } bprint "\n" ); } } DeallocateBuffer( Oplock->BufferIndex ); NtTerminateThread( NtCurrentThread(), STATUS_SUCCESS ); bprint "\nOplockBreakNotify: Thread not terminated\n" ); }