From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/dll/csrutil.c | 867 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 867 insertions(+) create mode 100644 private/ntos/dll/csrutil.c (limited to 'private/ntos/dll/csrutil.c') diff --git a/private/ntos/dll/csrutil.c b/private/ntos/dll/csrutil.c new file mode 100644 index 000000000..c8cf598ee --- /dev/null +++ b/private/ntos/dll/csrutil.c @@ -0,0 +1,867 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dllutil.c + +Abstract: + + This module contains utility procedures for the Windows Client DLL + + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Revision History: + +--*/ + +#include "csrdll.h" + +NTSTATUS +CsrClientCallServer( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_CAPTURE_HEADER CaptureBuffer OPTIONAL, + IN CSR_API_NUMBER ApiNumber, + IN ULONG ArgLength + ) + +/*++ + +Routine Description: + + This function sends an API request to the Windows Emulation Subsystem + Server and waits for a reply. + +Arguments: + + m - Pointer to the API request message to send. + + CaptureBuffer - Optional pointer to a capture buffer located in the + Port Memory section that contains additional data being sent + to the server. Since Port Memory is also visible to the server, + no data needs to be copied, but pointers to locations within the + capture buffer need to be converted into pointers valid in the + server's process context, since the server's view of the Port Memory + is not at the same virtual address as the client's view. + + ApiNumber - Small integer that is the number of the API being called. + + ArgLength - Length, in bytes, of the argument portion located at the + end of the request message. Used to calculate the length of the + request message. + +Return Value: + + Status Code from either client or server + +--*/ + +{ + NTSTATUS Status; + PULONG PointerOffsets; + ULONG CountPointers, Pointer; + + // + // Initialize the header of the message. + // + + if ((LONG)ArgLength < 0) { + ArgLength = (ULONG)(-(LONG)ArgLength); + m->h.u2.s2.Type = 0; + } + else { + m->h.u2.ZeroInit = 0; + } + + ArgLength |= (ArgLength << 16); + ArgLength += ((sizeof( CSR_API_MSG ) - sizeof( m->u )) << 16) | + (FIELD_OFFSET( CSR_API_MSG, u ) - sizeof( m->h )); + m->h.u1.Length = ArgLength; + m->CaptureBuffer = NULL; + m->ApiNumber = ApiNumber; + + // + // if the caller is within the server process, do the API call directly + // and skip the capture buffer fixups and LPC call. + // + + if (CsrServerProcess == FALSE) { + + // + // If the CaptureBuffer argument is present, then there is data located + // in the Port Memory section that is being passed to the server. All + // Port Memory pointers need to be converted so they are valid in the + // Server's view of the Port Memory. + // + + if (ARGUMENT_PRESENT( CaptureBuffer )) { + // + // Store a pointer to the capture buffer in the message that is valid + // in the server process's context. + // + + m->CaptureBuffer = (PCSR_CAPTURE_HEADER) + ((PCHAR)CaptureBuffer + CsrPortMemoryRemoteDelta); + + // + // Mark the fact that we are done allocating space from the end of + // the capture buffer. + // + + CaptureBuffer->FreeSpace = NULL; + + // + // Loop over all of the pointers to Port Memory within the message + // itself and convert them into server pointers. Also, convert + // the pointers to pointers into offsets. + // + + PointerOffsets = CaptureBuffer->MessagePointerOffsets; + CaptureBuffer->MessagePointerOffsets = (PULONG) + ((PCHAR)CaptureBuffer->MessagePointerOffsets + + CsrPortMemoryRemoteDelta); + CountPointers = CaptureBuffer->CountMessagePointers; + while (CountPointers--) { + Pointer = *PointerOffsets++; + if (Pointer != 0) { + *(PULONG)Pointer += CsrPortMemoryRemoteDelta; + PointerOffsets[ -1 ] = Pointer - (ULONG)m; + } + } + + // + // Loop over all of the pointers to Port Memory within the capture + // buffer and convert them into server pointers. Also, convert + // the pointers to pointers into offsets. + // + + PointerOffsets = CaptureBuffer->CapturePointerOffsets; + CaptureBuffer->CapturePointerOffsets = (PULONG) + ((PCHAR)CaptureBuffer->CapturePointerOffsets + + CsrPortMemoryRemoteDelta); + CountPointers = CaptureBuffer->CountCapturePointers; + while (CountPointers--) { + Pointer = *PointerOffsets++; + if (Pointer != 0) { + *(PULONG)Pointer += CsrPortMemoryRemoteDelta; + PointerOffsets[ -1 ] = Pointer - (ULONG)CaptureBuffer; + } + } + } + + // + // Send the request to the server and wait for a reply. The wait is + // NOT alertable, because ? FIX,FIX + // + + Status = NtRequestWaitReplyPort( CsrPortHandle, + (PPORT_MESSAGE)m, + (PPORT_MESSAGE)m + ); + // + // If the CaptureBuffer argument is present then reverse what we did + // to the pointers above so that the client side code can use them + // again. + // + + if (ARGUMENT_PRESENT( CaptureBuffer )) { + // + // Convert the capture buffer pointer back to a client pointer. + // + + m->CaptureBuffer = (PCSR_CAPTURE_HEADER) + ((PCHAR)m->CaptureBuffer - CsrPortMemoryRemoteDelta); + + // + // Loop over all of the pointers to Port Memory within the message + // itself and convert them into client pointers. Also, convert + // the offsets pointers to pointers into back into pointers + // + + CaptureBuffer->MessagePointerOffsets = (PULONG) + ((PCHAR)CaptureBuffer->MessagePointerOffsets - + CsrPortMemoryRemoteDelta); + PointerOffsets = CaptureBuffer->MessagePointerOffsets; + CountPointers = CaptureBuffer->CountMessagePointers; + while (CountPointers--) { + Pointer = *PointerOffsets++; + if (Pointer != 0) { + Pointer += (ULONG)m; + PointerOffsets[ -1 ] = Pointer; + *(PULONG)Pointer -= CsrPortMemoryRemoteDelta; + } + } + + // + // Loop over all of the pointers to Port Memory within the capture + // buffer and convert them into client pointers. Also, convert + // the offsets pointers to pointers into back into pointers + // + + CaptureBuffer->CapturePointerOffsets = (PULONG) + ((PCHAR)CaptureBuffer->CapturePointerOffsets - + CsrPortMemoryRemoteDelta); + PointerOffsets = CaptureBuffer->CapturePointerOffsets; + CountPointers = CaptureBuffer->CountCapturePointers; + while (CountPointers--) { + Pointer = *PointerOffsets++; + if (Pointer != 0) { + Pointer += (ULONG)CaptureBuffer; + PointerOffsets[ -1 ] = Pointer; + *(PULONG)Pointer -= CsrPortMemoryRemoteDelta; + } + } + } + + // + // Check for failed status and do something. + // + if (!NT_SUCCESS( Status )) { + IF_DEBUG { + if (Status != STATUS_PORT_DISCONNECTED && + Status != STATUS_INVALID_HANDLE + ) { + DbgPrint( "CSRDLL: NtRequestWaitReplyPort failed - Status == %X\n", + Status + ); + } + } + + m->ReturnValue = Status; + } + } + else { + m->h.ClientId = NtCurrentTeb()->ClientId; + Status = (CsrServerApiRoutine)((PCSR_API_MSG)m, + (PCSR_API_MSG)m + ); + + // + // Check for failed status and do something. + // + + if (!NT_SUCCESS( Status )) { + IF_DEBUG { + DbgPrint( "CSRDLL: Server side client call failed - Status == %X\n", + Status + ); + } + + m->ReturnValue = Status; + } + } + + // + // The value of this function is whatever the server function returned. + // + + return( m->ReturnValue ); +} + + +PCSR_CAPTURE_HEADER +CsrAllocateCaptureBuffer( + IN ULONG CountMessagePointers, + IN ULONG CountCapturePointers, + IN ULONG Size + ) + +/*++ + +Routine Description: + + This function allocates a buffer from the Port Memory section for + use by the client in capture arguments into Port Memory. In addition to + specifying the size of the data that needs to be captured, the caller + needs to specify how many pointers to captured data will be passed. + Pointers can be located in either the request message itself, and/or + the capture buffer. + +Arguments: + + CountMessagePointers - Number of pointers within the request message + that will point to locations within the allocated capture buffer. + + CountCapturePointers - Number of pointers within the capture buffer + that will point to other locations within the allocated capture + buffer. + + Size - Total size of the data that will be captured into the capture + buffer. + +Return Value: + + A pointer to the capture buffer header. + +--*/ + +{ + PCSR_CAPTURE_HEADER CaptureBuffer; + ULONG CountPointers; + + // + // Calculate the total number of pointers that will be passed + // + + CountPointers = CountMessagePointers + CountCapturePointers; + + // + // Calculate the total size of the capture buffer. This includes the + // header, the array of pointer offsets and the data length. We round + // the data length to a 32-bit boundary, assuming that each pointer + // points to data whose length is not aligned on a 32-bit boundary. + // + + if (Size >= MAXLONG) { + // + // Bail early if too big + // + return NULL; + } + Size += sizeof( CSR_CAPTURE_HEADER ) + (CountPointers * sizeof( PVOID )); + Size = (Size + (3 * (CountPointers+1))) & ~3; + + // + // Allocate the capture buffer from the Port Memory Heap. + // + + CaptureBuffer = RtlAllocateHeap( CsrPortHeap, MAKE_CSRPORT_TAG( CAPTURE_TAG ), Size ); + if (CaptureBuffer == NULL) { + + // + // FIX, FIX - need to attempt the receive lost reply messages to + // to see if they contain CaptureBuffer pointers that can be freed. + // + + return( NULL ); + } + + // + // Initialize the capture buffer header + // + + CaptureBuffer->Length = Size; + CaptureBuffer->CountMessagePointers = 0; + CaptureBuffer->CountCapturePointers = 0; + + // + // If there are pointers being passed then initialize the arrays of + // pointer offsets to zero. In either case set the free space pointer + // in the capture buffer header to point to the first 32-bit aligned + // location after the header, the arrays of pointer offsets are considered + // part of the header. + // + + if (CountPointers != 0) { + CaptureBuffer->MessagePointerOffsets = (PULONG)(CaptureBuffer + 1); + + CaptureBuffer->CapturePointerOffsets = + CaptureBuffer->MessagePointerOffsets + CountMessagePointers; + + RtlZeroMemory( CaptureBuffer->MessagePointerOffsets, + CountPointers * sizeof( ULONG ) + ); + + CaptureBuffer->FreeSpace = (PCHAR) + (CaptureBuffer->CapturePointerOffsets + CountCapturePointers); + } + else { + CaptureBuffer->MessagePointerOffsets = NULL; + CaptureBuffer->CapturePointerOffsets = NULL; + CaptureBuffer->FreeSpace = (PCHAR)(CaptureBuffer + 1); + } + + // + // Returned the address of the capture buffer. + // + + return( CaptureBuffer ); +} + + +VOID +CsrFreeCaptureBuffer( + IN PCSR_CAPTURE_HEADER CaptureBuffer + ) + +/*++ + +Routine Description: + + This function frees a capture buffer allocated by CsrAllocateCaptureBuffer. + +Arguments: + + CaptureBuffer - Pointer to a capture buffer allocated by + CsrAllocateCaptureBuffer. + +Return Value: + + None. + +--*/ + +{ + // + // Free the capture buffer back to the Port Memory heap. + // + + RtlFreeHeap( CsrPortHeap, 0, CaptureBuffer ); +} + + +ULONG +CsrAllocateMessagePointer( + IN OUT PCSR_CAPTURE_HEADER CaptureBuffer, + IN ULONG Length, + OUT PVOID *Pointer + ) + +/*++ + +Routine Description: + + This function allocates space from the capture buffer along with a + pointer to point to it. The pointer is presumed to be located in + the request message structure. + +Arguments: + + CaptureBuffer - Pointer to a capture buffer allocated by + CsrAllocateCaptureBuffer. + + Length - Size of data being allocated from the capture buffer. + + Pointer - Address of the pointer within the request message that + is to point to the space allocated out of the capture buffer. + +Return Value: + + The actual length of the buffer allocated, after it has been rounded + up to a multiple of 4. + +--*/ + +{ + if (Length == 0) { + *Pointer = NULL; + Pointer = NULL; + } + + else { + + // + // Set the returned pointer value to point to the next free byte in + // the capture buffer. + // + + *Pointer = CaptureBuffer->FreeSpace; + + // + // Round the length up to a multiple of 4 + // + + if (Length >= MAXLONG) { + // + // Bail early if too big + // + return 0; + } + + Length = (Length + 3) & ~3; + + // + // Update the free space pointer to point to the next available byte + // in the capture buffer. + // + + CaptureBuffer->FreeSpace += Length; + } + + + // + // Remember the location of this pointer so that CsrClientCallServer can + // convert it into a server pointer prior to sending the request to + // the server. + // + + CaptureBuffer->MessagePointerOffsets[ CaptureBuffer->CountMessagePointers++ ] = + (ULONG)Pointer; + + // + // Returned the actual length allocated. + // + + return( Length ); +} + + +ULONG +CsrAllocateCapturePointer( + IN OUT PCSR_CAPTURE_HEADER CaptureBuffer, + IN ULONG Length, + OUT PVOID *Pointer + ) +/*++ + +Routine Description: + + This function allocates space from the capture buffer along with a + pointer to point to it. The pointer is presumed to be located within + the capture buffer itself. + +Arguments: + + CaptureBuffer - Pointer to a capture buffer allocated by + CsrAllocateCaptureBuffer. + + Length - Size of data being allocated from the capture buffer. + + Pointer - Address of the pointer within the capture buffer that + is to point to the space allocated out of the capture buffer. + +Return Value: + + The actual length of the buffer allocated, after it has been rounded + up to a multiple of 4. + +--*/ + +{ + // + // Set the returned pointer value to point to the next free byte in + // the capture buffer. + // + + *Pointer = CaptureBuffer->FreeSpace; + + // + // Round the length up to a multiple of 4 + // + + Length = (Length + 3) & ~3; + + // + // Update the free space pointer to point to the next available byte in the + // capture buffer. + // + + CaptureBuffer->FreeSpace += Length; + + // + // Remember the location of this pointer so that CsrClientCallServer can + // convert it into a server pointer prior to sending the request to + // the server. + // + + CaptureBuffer->CapturePointerOffsets[ CaptureBuffer->CountCapturePointers++ ] = + (ULONG)Pointer; + + // + // Returned the actual length allocated. + // + + return( Length ); +} + + +VOID +CsrCaptureMessageBuffer( + IN OUT PCSR_CAPTURE_HEADER CaptureBuffer, + IN PVOID Buffer OPTIONAL, + IN ULONG Length, + OUT PVOID *CapturedBuffer + ) + +/*++ + +Routine Description: + + This function captures an ASCII string into a counted string data + structure located in an API request message. + +Arguments: + + CaptureBuffer - Pointer to a capture buffer allocated by + CsrAllocateCaptureBuffer. + + Buffer - Optional pointer to the buffer. If this parameter is + not present, then the counted string data structure is set to + the null string and no space is allocated from the capture + buffer. + + Length - Length of the buffer. + + CaptureString - Pointer to the field in the message that will + be filled in to point to the capture buffer. + +Return Value: + + None. + +--*/ + +{ + // + // Set the length fields of the captured string structure and allocated + // the Length for the string from the capture buffer. + // + + CsrAllocateMessagePointer( CaptureBuffer, + Length, + CapturedBuffer + ); + + // + // If Buffer parameter is not present or the length of the data is zero, + // return. + // + + if (!ARGUMENT_PRESENT( Buffer ) || (Length == 0)) { + return; + } + + // + // Copy the buffer data to the capture area. + // + + RtlMoveMemory( *CapturedBuffer, Buffer, Length ); + + return; +} + +VOID +CsrCaptureMessageString( + IN OUT PCSR_CAPTURE_HEADER CaptureBuffer, + IN PCSTR String OPTIONAL, + IN ULONG Length, + IN ULONG MaximumLength, + OUT PSTRING CapturedString + ) + +/*++ + +Routine Description: + + This function captures an ASCII string into a counted string data + structure located in an API request message. + +Arguments: + + CaptureBuffer - Pointer to a capture buffer allocated by + CsrAllocateCaptureBuffer. + + String - Optional pointer to the ASCII string. If this parameter is + not present, then the counted string data structure is set to + the null string and no space is allocated from the capture + buffer. + + Length - Length of the ASCII string. + + MaximumLength - Maximum length of the string. Different for null + terminated strings, where Length does not include the null and + MaximumLength does. + + CaptureString - Pointer to the counted string data structure that will + be filled in to point to the capture ASCII string. + +Return Value: + + None. + +--*/ + +{ + // + // If String parameter is not present, then set the captured string + // to be the null string and returned. + // + + if (!ARGUMENT_PRESENT( String )) { + CapturedString->Length = 0; + CapturedString->MaximumLength = (USHORT)MaximumLength; + CsrAllocateMessagePointer( CaptureBuffer, + MaximumLength, + (PVOID *)&CapturedString->Buffer + ); + return; + } + + // + // Set the length fields of the captured string structure and allocated + // the MaximumLength for the string from the capture buffer. + // + + CapturedString->Length = (USHORT)Length; + CapturedString->MaximumLength = (USHORT) + CsrAllocateMessagePointer( CaptureBuffer, + MaximumLength, + (PVOID *)&CapturedString->Buffer + ); + // + // If the Length of the ASCII string is non-zero then move it to the + // capture area. + // + + if (Length != 0) { + RtlMoveMemory( CapturedString->Buffer, String, MaximumLength ); + if (CapturedString->Length < CapturedString->MaximumLength) { + CapturedString->Buffer[ CapturedString->Length ] = '\0'; + } + } + + return; +} + + + +PLARGE_INTEGER +CsrCaptureTimeout( + IN ULONG MilliSeconds, + OUT PLARGE_INTEGER Timeout + ) +{ + if (MilliSeconds == -1) { + return( NULL ); + } + else { + Timeout->QuadPart = Int32x32To64( MilliSeconds, -10000 ); + return( (PLARGE_INTEGER)Timeout ); + } +} + +VOID +CsrProbeForWrite( + IN PVOID Address, + IN ULONG Length, + IN ULONG Alignment + ) + +/*++ + +Routine Description: + + This function probes a structure for read accessibility. + If the structure is not accessible, then an exception is raised. + +Arguments: + + Address - Supplies a pointer to the structure to be probed. + + Length - Supplies the length of the structure. + + Alignment - Supplies the required alignment of the structure expressed + as the number of bytes in the primitive datatype (e.g., 1 for char, + 2 for short, 4 for long, and 8 for quad). + +Return Value: + + None. + +--*/ + +{ + volatile CHAR *StartAddress; + volatile CHAR *EndAddress; + CHAR Temp; + + // + // If the structure has zero length, then do not probe the structure for + // write accessibility or alignment. + // + + if (Length != 0) { + + // + // If the structure is not properly aligned, then raise a data + // misalignment exception. + // + + ASSERT((Alignment == 1) || (Alignment == 2) || + (Alignment == 4) || (Alignment == 8)); + StartAddress = (volatile CHAR *)Address; + + if (((ULONG)StartAddress & (Alignment - 1)) != 0) { + RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT); + } else { + // + // BUG, BUG - this should not be necessary once the 386 kernel + // makes system space inaccessable to user mode. + // + if ((ULONG)StartAddress > CsrNtSysInfo.MaximumUserModeAddress) { + RtlRaiseStatus(STATUS_ACCESS_VIOLATION); + } + + Temp = *StartAddress; + *StartAddress = Temp; + EndAddress = StartAddress + Length - 1; + Temp = *EndAddress; + *EndAddress = Temp; + } + } +} + +VOID +CsrProbeForRead( + IN PVOID Address, + IN ULONG Length, + IN ULONG Alignment + ) + +/*++ + +Routine Description: + + This function probes a structure for read accessibility. + If the structure is not accessible, then an exception is raised. + +Arguments: + + Address - Supplies a pointer to the structure to be probed. + + Length - Supplies the length of the structure. + + Alignment - Supplies the required alignment of the structure expressed + as the number of bytes in the primitive datatype (e.g., 1 for char, + 2 for short, 4 for long, and 8 for quad). + +Return Value: + + None. + +--*/ + +{ + volatile CHAR *StartAddress; + volatile CHAR *EndAddress; + CHAR Temp; + + // + // If the structure has zero length, then do not probe the structure for + // read accessibility or alignment. + // + + if (Length != 0) { + + // + // If the structure is not properly aligned, then raise a data + // misalignment exception. + // + + ASSERT((Alignment == 1) || (Alignment == 2) || + (Alignment == 4) || (Alignment == 8)); + StartAddress = (volatile CHAR *)Address; + + if (((ULONG)StartAddress & (Alignment - 1)) != 0) { + RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT); + } else { + Temp = *StartAddress; + EndAddress = StartAddress + Length - 1; + Temp = *EndAddress; + } + } +} -- cgit v1.2.3