/*++ Copyright (c) 1991-92 Microsoft Corporation Module Name: XsSubs.c Abstract: This module contains various subroutines for XACTSRV. Author: David Treadwell (davidtr) 07-Jan-1991 Revision History: 05-Oct-1992 JohnRo RAID 3556: DosPrintQGetInfo(from downlevel) level 3, rc=124. (4&5 too.) (Fixed XsFillAuxEnumBuffer.) --*/ #include "XactSrvP.h" #include // GetCurrentProcessId prototype #include VOID SmbCapturePtr( LPBYTE PointerDestination, LPBYTE PointerSource ); DWORD XsBytesForConvertedStructure ( IN LPBYTE InStructure, IN LPDESC InStructureDesc, IN LPDESC OutStructureDesc, IN RAP_CONVERSION_MODE Mode, IN BOOL MeaninglessInputPointers ) /*++ Routine Description: This routine determines the number of bytes that would be required to hold the input structure when converted to the structure described by OutStructureDesc. Arguments: InStructure - a pointer to the actual input structure. InStructureDesc - a pointer to an ASCIIZ describing the format of the input structure. OutStructureDesc - a pointer to an ASCIIZ describing the format of the output structure. Mode - indicates mode of conversion (native to RAP or vice versa). Return Value: DWORD - The number of bytes required to hold the converted structure. --*/ { NET_API_STATUS status; DWORD bytesRequired = 0; // // Use RapConvertSingleEntry to get the size that the input structure // will take when converted to the format specified in the output // structure description. That routine should not actually write // anything--it should simply appear that there is no room to // write more data into, just as if an Enum buffer is full. // // // Should handle errors from RapConvertSingleEntry. // But the way this is used, existing code probably // won't break if we just ignore them. // status = RapConvertSingleEntry( InStructure, InStructureDesc, MeaninglessInputPointers, NULL, NULL, OutStructureDesc, FALSE, NULL, &bytesRequired, Response, Mode ); // // For native structures, we should make sure the buffer is an even amount, // to allow an even boundary for strings, as in Unicode. // if ( Mode == RapToNative ) { bytesRequired = ROUND_UP_COUNT( bytesRequired, ALIGN_DWORD ); } return bytesRequired; } // XsBytesForConvertedStructure LPVOID XsCaptureParameters ( IN LPTRANSACTION Transaction, OUT LPDESC *AuxDescriptor ) /*++ Routine Description: This routine captures all input parameters from the transaction block and puts them into a consistent structure that API handlers can access. It allocates memory to hold this structure. This memory should be freed by XsSetParameters after the API handler has done its work. Arguments: Transaction - a pointer to the transaction block describing the request. AuxDescriptor - a pointer to a LPDESC which will hold a pointer to the auxiliary descriptor string if there is one, or NULL if there is not. Return Value: LPVOID - a pointer to a buffer containing the captured parameters. --*/ { LPDESC descriptorString; LPDESC descriptor; LPBYTE inParams; DWORD outParamsLength; LPBYTE outParams; LPBYTE outParamsPtr; WORD rcvBufferLength; // // The first two bytes of the parameter section are the API number, // then comes the descriptor string. // descriptorString = Transaction->InParameters + 2; // // Find the actual parameter data in the input. // inParams = XsFindParameters( Transaction ); // // Find out how much space to allocate to hold the parameters. // outParamsLength = RapStructureSize( descriptorString, Response, FALSE ); // // Allocate space to hold the output parameters. // In addition when the request fails the current APIs set the buflen field // In order to account for this additional buffer space is allocated. Since // this field is not located at the same offset we need to compute the // additional space reqd. to be the maximum of all the offsets. Currently // the 16 byte offset seems to suffice. When modifying apiparam.h ensure // that this is the case. // outParams = NetpMemoryAllocate( sizeof(XS_PARAMETER_HEADER) + outParamsLength + sizeof(DWORD) * 4); if ( outParams == NULL ) { IF_DEBUG(ERRORS) { NetpKdPrint(( "XsCaptureParameters: unable to allocate %ld bytes\n", outParamsLength )); } return NULL; } // // Zero out the parameters and set outParamsPtr to the start of the // actual parameters. // RtlZeroMemory( outParams, sizeof(XS_PARAMETER_HEADER) + outParamsLength ); outParamsPtr = outParams + sizeof(XS_PARAMETER_HEADER); // // For each character in the descriptor string, fill in the output // parameters as appropriate. // for ( descriptor = descriptorString; *descriptor != '\0'; ) { switch ( *descriptor++ ) { case REM_ASCIZ: // // The parameter is a pointer to a string. The actual string // is in the parameter data, so put a pointer to it in the // output structure. // // String parameters just get passed as is. It // is up to the API handler to convert the actual data. // // // !!! Parameter string descriptors may not have maximum length // counts. // if( isdigit( *descriptor ) ) { NetpMemoryFree( outParams ); return NULL; } SmbCapturePtr( outParamsPtr, inParams ); // // Update pointers -- move inParams past end of string. // inParams += ( strlen( inParams ) + 1 ); outParamsPtr += sizeof(LPSTR); break; case REM_BYTE_PTR: case REM_FILL_BYTES: // // The parameter is a pointer to a byte or array of bytes. // SmbCapturePtr( outParamsPtr, inParams ); inParams += sizeof(BYTE) * RapDescArrayLength( descriptor ); outParamsPtr += sizeof(LPBYTE); break; case REM_DWORD: // // The parameter is a dword or array of dwords. // // !!! This assumes that an array of words will never be passed // as a parameter. if( isdigit( *descriptor ) ) { NetpMemoryFree( outParams ); return NULL; } // // Copy over the double word and update pointers. // SmbPutUlong( (LPDWORD)outParamsPtr, SmbGetUlong( (LPDWORD)inParams ) ); inParams += sizeof(DWORD); outParamsPtr += sizeof(DWORD); break; case REM_ENTRIES_READ: case REM_RCV_WORD_PTR: // // Count of entries read (e) or receive word pointer (h). // This is an output parameter, so just zero it and // increment the output parameter pointer. // SmbPutUshort( (LPWORD)outParamsPtr, 0 ); outParamsPtr += sizeof(WORD); break; case REM_RCV_DWORD_PTR: // // Count of receive dword pointer (i). // This is an output parameter, so just zero it and // increment the output parameter pointer. // SmbPutUlong( (LPDWORD)outParamsPtr, 0 ); outParamsPtr += sizeof(DWORD); break; case REM_NULL_PTR: // // Null pointer. Set output parameter to NULL, and increment // pointers. // SmbCapturePtr( outParamsPtr, NULL ); outParamsPtr += sizeof(LPSTR); break; case REM_RCV_BUF_LEN: // // The length of the receive buffer (r). // rcvBufferLength = SmbGetUshort( (LPWORD)inParams ); // // If the indicated buffer length is greater than the max // data count on the transaction, somebody messed up. Set // the length to MaxDataCount. // if ( rcvBufferLength > (WORD)Transaction->MaxDataCount ) { IF_DEBUG(ERRORS) { NetpKdPrint(( "XsCaptureParameters: OutBufLen %lx greater than MaxDataCount %lx.\n", rcvBufferLength, Transaction->MaxDataCount )); } rcvBufferLength = (WORD)Transaction->MaxDataCount; } // // Put the max output data length in the output parameters. // SmbPutUshort( (LPWORD)outParamsPtr, rcvBufferLength ); // // Fill in the receive buffer with zeroes for security. // RtlZeroMemory( Transaction->OutData, (DWORD)rcvBufferLength ); inParams += sizeof(WORD); outParamsPtr += sizeof(WORD); break; case REM_RCV_BUF_PTR: // // A pointer to a receive data buffer. There is nothing in // the transaction corresponding to this, but set a longword // in the output parameters to point to the data output // section of the transaction. // SmbCapturePtr( outParamsPtr, Transaction->OutData ); outParamsPtr += sizeof(LPBYTE); break; case REM_RCV_BYTE_PTR: // // Return bytes, so just increment output parameter pointer. // outParamsPtr += sizeof(BYTE) * RapDescArrayLength( descriptor ); break; case REM_SEND_BUF_LEN: // // The size of an input data buffer. Put the size of the // received data in the output structure. // SmbPutUshort( (LPWORD)outParamsPtr, (WORD)Transaction->DataCount ); outParamsPtr += sizeof(WORD); break; case REM_SEND_BUF_PTR: // // A pointer to a send data buffer. There is nothing in the // transaction corresponding to this, but set a longword in // the output parameters to point to the data input section // of the transaction. // SmbCapturePtr( outParamsPtr, Transaction->InData ); outParamsPtr += sizeof(LPBYTE); break; case REM_WORD: case REM_PARMNUM: // // The parameter is a word. // // !!! This assumes that an array of words will never be passed // as a parameter. if( isdigit( *descriptor ) ) { NetpMemoryFree( outParams ); return NULL; } // // Copy over the word and update pointers. // SmbPutUshort( (LPWORD)outParamsPtr, SmbGetUshort( (LPWORD)inParams ) ); inParams += sizeof(WORD); outParamsPtr += sizeof(WORD); break; default: IF_DEBUG(ERRORS) { NetpKdPrint(( "XsCaptureParameters: unsupported character at %lx: " "%c\n", descriptor - 1, *( descriptor - 1 ) )); NetpBreakPoint( ); } } } // // Examine the data descriptor string to see if an auxiliary descriptor // string exists. If it does, the string starts right after the end // of the parameters. // *AuxDescriptor = XsAuxiliaryDescriptor( ++descriptor, inParams ); return outParams; } // XsCaptureParameters BOOL XsCheckBufferSize ( IN WORD BufferLength, IN LPDESC Descriptor, IN BOOL NativeFormat ) /*++ Routine Description: This routine determines if there is enough room in the buffer for the fixed component of at least one entry of the described structure. Arguments: BufferLength - the length of the buffer to test. Descriptor - the format of the structure in the buffer. NativeFormat - TRUE iff the buffer is in native (as opposed to RAP) format. Return Value: BOOL - True if there is enough room, false if there isn't. --*/ { if ( (DWORD)BufferLength >= RapStructureSize( Descriptor, Response, NativeFormat )) { return TRUE; } else { return FALSE; } } // XsCheckBufferSize BOOL XsCheckSmbDescriptor( IN LPDESC SmbDescriptor, IN LPDESC ActualDescriptor ) /*++ Routine Description: This routine checks whether a descriptor passed in the SMB matches the actual descriptor expected, taking into account that the actual descriptor may have ignore fields which have no corresponding field in the SMB descriptor, and that the SMB descriptor may have null pointer fields instead of normal pointer fields. However, array-type fields have to be of the same length in both descriptors. Arguments: SmbDescriptor - the descriptor to be validated. ActualDescriptor - the descriptor expected. Does not have to be an exact match - see the description above. Return Value: BOOL - TRUE if the descriptor is valid, FALSE otherwise. --*/ { DESC_CHAR smbField; DESC_CHAR expField; DWORD smbFieldSize; DWORD expFieldSize; CHAR nullParam = '\0'; if( ActualDescriptor == NULL ) { ActualDescriptor = &nullParam; } while (( smbField = *SmbDescriptor++ ) != '\0' ) { smbFieldSize = RapDescArrayLength( SmbDescriptor ); // // Skip over ignore fields. // while ( *ActualDescriptor == REM_IGNORE ) { ActualDescriptor++; } // // There should be a corresponding field expected. // if (( expField = *ActualDescriptor++ ) == '\0' ) { return FALSE; } expFieldSize = RapDescArrayLength( ActualDescriptor ); // // If both are actual data fields, they must be the same type and of // same length. // if (( !RapIsPointer( expField ) || smbField != REM_NULL_PTR ) && ( smbField != expField || smbFieldSize != expFieldSize )) { return FALSE; } // // SMB provides a null pointer field, we are expecting any pointer. // This is OK, as long as there is no input array length. // if ( smbField == REM_NULL_PTR && ( !RapIsPointer( expField ) || smbFieldSize != 1 )) { return FALSE; } } while ( *ActualDescriptor == REM_IGNORE ) { ActualDescriptor++; } // // Validate that the entire descriptor was present! // if( (*ActualDescriptor) != '\0' ) { return FALSE; } return TRUE; } // XsCheckSmbDescriptor NET_API_STATUS XsConvertSetInfoBuffer( IN LPBYTE InBuffer, IN WORD BufferLength, IN WORD ParmNum, IN BOOL ConvertStrings, IN BOOL MeaninglessInputPointers, IN LPDESC InStructureDesc, IN LPDESC OutStructureDesc, IN LPDESC InSetInfoDesc, IN LPDESC OutSetInfoDesc, OUT LPBYTE * OutBuffer, OUT LPDWORD OutBufferLength OPTIONAL ) /*++ Routine Description: This routine converts data for a SetInfo call based on the parameter number (ParmNum) value. The ParmNum indicates the field in the whole structure which has to be changed, and may be 0. Arguments: InBuffer - a pointer to the input buffer in 16-bit format. BufferLength - the length of the input buffer. ParmNum - the parameter number. ConvertStrings - a boolean indicating whether string parameter data should be converted to a pointer form. If TRUE, the return data buffer will have a pointer to another place in the buffer where the string will be. If FALSE, the data buffer will have only the physical string. InStructureDesc - the exact descriptor of the input buffer. OutStructureDesc - the descriptor of the 32-bit output data, as found in RemDef.h. InSetInfoDesc - the setinfo-specific descriptor of the input structure format, as found in RemDef.h. OutSetInfoDesc - the setinfo-specific descriptor of the output structure format, as found in RemDef.h. OutBuffer - a pointer to an LPBYTE which will get a pointer to the resulting output buffer. OutBufferLength - an optional pointer to a DWORD which will get the length of the resulting output buffer. Return Value: NET_API_STATUS - NERR_Success if conversion was successful; otherwise the appropriate status to return to the user. The only exception is ERROR_NOT_SUPPORTED, which indicates that the particular parameter number is valid, but not on NT. --*/ { LPDESC fieldDesc = NULL; DWORD stringLength; LPDESC subDesc = NULL; LPDESC subDesc2 = NULL; DWORD bufferSize; LPBYTE stringLocation; DWORD bytesRequired = 0; LPDESC OutDescCopy = OutStructureDesc; NET_API_STATUS status = NERR_Success; // // The buffer length should be greater than 0. // if ( BufferLength == 0 ) { return NERR_BufTooSmall; } if ( ParmNum != PARMNUM_ALL ) { // // Check 16-bit parameter to see if it could be changed in OS/2. // fieldDesc = RapParmNumDescriptor( InSetInfoDesc, (DWORD)ParmNum, Both, FALSE ); if ( fieldDesc == NULL ) { return NERR_NoRoom; } if ( fieldDesc[0] == REM_UNSUPPORTED_FIELD ) { status = ERROR_INVALID_PARAMETER; goto cleanup; } else { InStructureDesc = RapParmNumDescriptor( InStructureDesc, (DWORD)ParmNum, Both, FALSE ); } NetpMemoryFree( fieldDesc ); // // Check 32-bit parameter to see if it is valid in NT. // fieldDesc = RapParmNumDescriptor( OutSetInfoDesc, (DWORD)ParmNum, Both, TRUE ); if ( fieldDesc == NULL ) { return NERR_NoRoom; } if ( fieldDesc[0] == REM_IGNORE ) { status = ERROR_NOT_SUPPORTED; goto cleanup; } else { OutStructureDesc = RapParmNumDescriptor( OutStructureDesc, (DWORD)ParmNum, Both, TRUE ); } // // Filter out strings that are too long for LM2.x. // if ( InStructureDesc[0] == REM_ASCIZ || InStructureDesc[0] == REM_ASCIZ_TRUNCATABLE ) { subDesc = InStructureDesc + 1; stringLength = RapDescStringLength( subDesc ); subDesc = NULL; if ( stringLength && strlen( InBuffer ) >= stringLength ) { switch( InStructureDesc[0] ) { case REM_ASCIZ: status = ERROR_INVALID_PARAMETER; goto cleanup; case REM_ASCIZ_TRUNCATABLE: InBuffer[stringLength - 1] = '\0'; } } } // // If a descriptor is a string pointer, the data is the actual // string, rather than a pointer. Find the length of the string, // and create a descriptor. // // Assuming all these arrays are string data, we // use available macros to generate an array big // enough to hold the converted string. if ( InStructureDesc[0] == REM_ASCIZ || InStructureDesc[0] == REM_ASCIZ_TRUNCATABLE ) { if (( subDesc = NetpMemoryAllocate( MAX_DESC_SUBSTRING + 1 )) == NULL ) { status = NERR_NoRoom; goto cleanup; } stringLength = strlen( InBuffer ) + 1; subDesc[0] = REM_BYTE; _ltoa( stringLength, &subDesc[1], 10 ); InStructureDesc = subDesc; } // // If output descriptor is a string pointer, and we are asked to keep // strings inline, make the target data an array of bytes. We find out // the length required by "walking" the input descriptor, and then // allocate memory to hold a similar descriptor. // // Assuming all these arrays are string data, we // use available macros to generate an array big // enough to hold the converted string. Because of the way // RAP works, if the destination string is Unicode, the destination // array will be exactly twice as long, and RAP will automatically // do the Unicode conversion. // if (( OutStructureDesc[0] == REM_ASCIZ || OutStructureDesc[0] == REM_ASCIZ_TRUNCATABLE ) && !ConvertStrings ) { OutDescCopy = OutStructureDesc; subDesc2 = InStructureDesc + 1; stringLength = RapDescArrayLength( subDesc2 ); if (( subDesc2 = NetpMemoryAllocate( MAX_DESC_SUBSTRING + 1 )) == NULL ) { status = NERR_NoRoom; goto cleanup; } subDesc2[0] = REM_BYTE; _ltoa( STRING_SPACE_REQD( stringLength ), &subDesc2[1], 10 ) ; OutStructureDesc = subDesc2; } } if ( !XsCheckBufferSize( BufferLength, InStructureDesc, FALSE )) { status = NERR_BufTooSmall; goto cleanup; } // // Find out how big a 32-bit data buffer we need. // bufferSize = XsBytesForConvertedStructure( InBuffer, InStructureDesc, OutStructureDesc, RapToNative, MeaninglessInputPointers ); // // Allocate enough memory to hold the converted native buffer. // *OutBuffer = NetpMemoryAllocate( bufferSize ); if ( *OutBuffer == NULL ) { status = NERR_NoRoom; goto cleanup; } // // Convert 16-bit data into 32-bit data and store it in the native // buffer. // stringLocation = *OutBuffer + bufferSize; bytesRequired = 0; status = RapConvertSingleEntry( InBuffer, InStructureDesc, MeaninglessInputPointers, *OutBuffer, *OutBuffer, OutStructureDesc, FALSE, &stringLocation, &bytesRequired, Response, RapToNative ); if ( status != NERR_Success ) { IF_DEBUG(ERRORS) { NetpKdPrint(( "XsConvertSetInfoBuffer: RapConvertSingleEntry " "failed %X\n", status )); } status = NERR_InternalError; goto cleanup; } cleanup: // // Free buffers. // NetpMemoryFree( subDesc ); NetpMemoryFree( subDesc2 ); NetpMemoryFree( fieldDesc ); if ( OutBufferLength != NULL ) { *OutBufferLength = bytesRequired; } return status; } // XsConvertSetInfoBuffer NET_API_STATUS XsDefaultEnumVerifyFunction ( NET_API_STATUS ConvertStatus, PBYTE ConvertedEntry, PBYTE BaseAddress ) /*++ Routine Description: This is the default routine called by XsFillEnumBuffer to determine whether each converted entry should be retained or discarded. This routine directs XsFillEnumBuffer to discard any entry which RapConvertSingleEntry encountered an error trying to convert. Parameters: ConvertStatus - the status which RapConvertSingleEntry encountered trying to convert this entry. ConvertedEntry - a pointer to the buffer containing the converted entry. BaseAddress - A pointer to the base used to calculate offsets. Return Value: NET_API_STATUS - NERR_Success if the entry should be retained, or an error code if the entry should be discarded. --*/ { UNREFERENCED_PARAMETER(ConvertedEntry); UNREFERENCED_PARAMETER(BaseAddress); return ConvertStatus; } VOID XsFillAuxEnumBuffer ( IN LPBYTE InBuffer, IN DWORD NumberOfEntries, IN LPDESC InStructureDesc, IN LPDESC InAuxStructureDesc, IN OUT LPBYTE OutBuffer, IN LPBYTE OutBufferStart, IN DWORD OutBufferLength, IN LPDESC OutStructureDesc, IN LPDESC OutAuxStructureDesc, IN PXACTSRV_ENUM_VERIFY_FUNCTION VerifyFunction OPTIONAL, OUT LPDWORD BytesRequired, OUT LPDWORD EntriesFilled, OUT LPDWORD InvalidEntries OPTIONAL ) /*++ Routine Description: This routine copies all Enum structures which have auxiliary data from 32-bit format to 16-bit format. As many complete entries as possible are copied, then possibly some incomplete entries. All pointer fields are converted to offsets so that this buffer may be returned directly to the requesting client. Enum buffers with auxiliary data have one or more auxiliary structures, with possible variable data, after each entry. Arguments: InBuffer - a pointer to the input information in 32-bit format. NumberOfEntries - the count of fixed structures in the input buffer. InStructureDesc - description of the input fixed structure. InAuxStructureDesc - description of the input auxiliary structure. OutBuffer - a pointer to where to write the 16-bit buffer. OutBufferStart - a pointer to the actual start of the 16-bit buffer. Used to calculate offsets for all pointers in structures. OutBufferLength - length of the output buffer. OutStructureDesc - description of the output fixed structure. OutAuxStructureDesc - description of the output fixed structure. VerifyFunction - a pointer to a function which is be called after each enum record is converted in order to determine whether the record should be retained or discarded. The function is passed the return code from RapConvertSingleEntry and a pointer to the converted entry. It must return NERR_SUCCESS if the entry is to be retained, or any error code if the entry is to be discarded. If no function is supplied, a default function is used, which discards an entry only if RapConvertSingleEntry returned an error trying to convert it. BytesRequired - a pointer to a DWORD to receive the total number of bytes that would be required to hold the entire output buffer. EntriesFilled - a pointer to a DWORD to receive the total number of entries that could be put in the buffer given. InvalidEntries - an optional pointer to a DWORD to receive the total number of entries discarded by the verify function. If NULL, this value will be not be available to the caller. Return Value: None. --*/ { NET_API_STATUS status; DWORD currentEntry; LPBYTE currentInEntryPtr; LPBYTE currentOutEntryPtr; LPBYTE outputStringLocation; LPBYTE oldStringLocation; DWORD inputStructureSize; DWORD inputAuxStructureSize; DWORD outputStructureSize; DWORD outputAuxStructureSize; DWORD inputAuxCount; DWORD currentAux; DWORD outputAuxOffset; DWORD newBytesRequired; DWORD auxBytesRequired; DWORD remainingSize; DWORD invalidEntries = 0; // // In degenerate case, just call FillEnumBuffer. // if ( InAuxStructureDesc == NULL || OutAuxStructureDesc == NULL ) { XsFillEnumBuffer ( InBuffer, NumberOfEntries, InStructureDesc, OutBuffer, OutBufferStart, OutBufferLength, OutStructureDesc, VerifyFunction, BytesRequired, EntriesFilled, InvalidEntries ); return; } if ( VerifyFunction == NULL ) { VerifyFunction = &XsDefaultEnumVerifyFunction; } // // Set up sizes of input and output structures. // inputStructureSize = RapStructureSize( InStructureDesc, Response, TRUE ); inputAuxStructureSize = RapStructureSize( InAuxStructureDesc, Response, TRUE ); outputStructureSize = RapStructureSize( OutStructureDesc, Response, FALSE ); outputAuxStructureSize = RapStructureSize( OutAuxStructureDesc, Response, FALSE ); outputAuxOffset = RapAuxDataCountOffset( InStructureDesc, Response, TRUE ); outputStringLocation = (LPBYTE)OutBuffer + OutBufferLength; *BytesRequired = 0; // // Check if one fixed entry will fit. // if ( inputStructureSize > OutBufferLength ) { *EntriesFilled = 0; goto cleanup; } // // Loop through the entries, converting along the way. // currentInEntryPtr = InBuffer; currentOutEntryPtr = OutBuffer; *EntriesFilled = 0; for ( currentEntry = 0; currentEntry < NumberOfEntries; currentEntry++ ) { // // If there wasn't enough room for the conversion, we can quit now. // if ( currentOutEntryPtr + outputStructureSize > outputStringLocation ) { break; } newBytesRequired = *BytesRequired; oldStringLocation = outputStringLocation; // // Get the auxiliary number count. // inputAuxCount = RapAuxDataCount( currentInEntryPtr, InStructureDesc, Response, TRUE ); NetpAssert( inputAuxCount != NO_AUX_DATA ); // // Convert the fixed entry. // status = RapConvertSingleEntry( currentInEntryPtr, InStructureDesc, FALSE, OutBufferStart, currentOutEntryPtr, OutStructureDesc, TRUE, &outputStringLocation, &newBytesRequired, Response, NativeToRap ); // // Check if the entry is valid. If it is not, fix up pointers, // and start with the next entry in the list. // If there are more than 65536 auxiliary structures (which // probably never happens anyway), this entry is automatically // invalid. // status = (*VerifyFunction)( status, currentOutEntryPtr, OutBufferStart ); if ( status != NERR_Success || inputAuxCount > 0xFFFF ) { invalidEntries++; currentInEntryPtr += inputStructureSize + inputAuxCount * inputAuxStructureSize; outputStringLocation = oldStringLocation; continue; } // // Prepare pointers for converting the auxiliary structures. // currentInEntryPtr += inputStructureSize; currentOutEntryPtr += outputStructureSize; // // Try to add the auxiliary structures. // for ( currentAux = 0; currentAux < inputAuxCount; currentAux++ ) { remainingSize = (DWORD)(outputStringLocation - currentOutEntryPtr); auxBytesRequired = 0; status = RapConvertSingleEntry( currentInEntryPtr, InAuxStructureDesc, FALSE, OutBufferStart, currentOutEntryPtr, OutAuxStructureDesc, TRUE, &outputStringLocation, &auxBytesRequired, Response, NativeToRap ); // // Did this aux. entry fit? If all the aux. entries do not fit, // we are going to play it safe and say the main entry did not // fit. // if ( status != NERR_Success || auxBytesRequired > remainingSize ) { goto cleanup; } currentInEntryPtr += inputAuxStructureSize; currentOutEntryPtr += outputAuxStructureSize; newBytesRequired += auxBytesRequired; } *BytesRequired = newBytesRequired; *EntriesFilled += 1; } cleanup: if ( InvalidEntries != NULL ) { *InvalidEntries = invalidEntries; } return; } // XsFillAuxEnumBuffer VOID XsFillEnumBuffer ( IN LPBYTE InBuffer, IN DWORD NumberOfEntries, IN LPDESC InStructureDesc, IN OUT LPBYTE OutBuffer, IN LPBYTE OutBufferStart, IN DWORD OutBufferLength, IN LPDESC OutStructureDesc, IN PXACTSRV_ENUM_VERIFY_FUNCTION VerifyFunction OPTIONAL, OUT LPDWORD BytesRequired, OUT LPDWORD EntriesFilled, OUT LPDWORD InvalidEntries OPTIONAL ) /*++ Routine Description: This routine copies all Enum structures from 32-bit format to 16-bit format. As many complete entries as possible are copied, then possibly some incomplete entries. All pointer fields are converted to offsets so that this buffer may be returned directly to the requesting client. Arguments: InBuffer - a pointer to the input information in 32-bit format. NumberOfEntries - the count of fixed structures in the input buffer. InStructureDesc - description of the input fixed structure. OutBuffer - a pointer to where to write the 16-bit buffer. OutBufferStart - a pointer to the actual start of the 16-bit buffer. Used to calculate offsets for all pointers in structures. OutBufferLength - length of the output buffer. OutStructureDesc - description of the output fixed structure. VerifyFunction - a pointer to a function which is be called after each enum record is converted in order to determine whether the record should be retained or discarded. The function is passed the return code from RapConvertSingleEntry and a pointer to the converted entry. It must return NERR_SUCCESS if the entry is to be retained, or any error code if the entry is to be discarded. If no function is supplied, a default function is used, which discards an entry only if RapConvertSingleEntry returned an error trying to convert it. BytesRequired - a pointer to a DWORD to receive the total number of bytes that would be required to hold the entire output buffer. EntriesFilled - a pointer to a DWORD to receive the total number of entries that could be put in the buffer given. InvalidEntries - an optional pointer to a DWORD to receive the total number of entries discarded by the verify function. If NULL, this value will be not be available to the caller. Return Value: None. --*/ { NET_API_STATUS status; DWORD currentEntry; LPBYTE currentInEntryPtr; LPBYTE currentOutEntryPtr; LPBYTE outputStringLocation; LPBYTE oldStringLocation; DWORD inputStructureSize; DWORD outputStructureSize; DWORD newBytesRequired; DWORD invalidEntries = 0; if ( VerifyFunction == NULL ) { VerifyFunction = &XsDefaultEnumVerifyFunction; } // // Set up sizes of input and output structures. // inputStructureSize = RapStructureSize( InStructureDesc, Response, TRUE ); outputStructureSize = RapStructureSize( OutStructureDesc, Response, FALSE ); outputStringLocation = (LPBYTE)OutBuffer + OutBufferLength; *BytesRequired = 0; // // Check if one fixed entry will fit. // if ( inputStructureSize > OutBufferLength ) { *EntriesFilled = 0; goto cleanup; } // // Loop through the entries, converting along the way. // currentInEntryPtr = InBuffer; currentOutEntryPtr = OutBuffer; *EntriesFilled = 0; for ( currentEntry = 0; currentEntry < NumberOfEntries; currentEntry++ ) { // // If there wasn't enough room for the conversion, we can quit now. // if ( currentOutEntryPtr + outputStructureSize > outputStringLocation ) { break; } newBytesRequired = *BytesRequired; oldStringLocation = outputStringLocation; status = RapConvertSingleEntry( currentInEntryPtr, InStructureDesc, FALSE, OutBufferStart, currentOutEntryPtr, OutStructureDesc, TRUE, &outputStringLocation, &newBytesRequired, Response, NativeToRap ); // // If the conversion was successful, increment the buffer pointers, // the count of bytes required, and the number of converted entries. // status = (*VerifyFunction)( status, currentOutEntryPtr, OutBufferStart ); if ( status == NERR_Success ) { currentInEntryPtr += inputStructureSize; currentOutEntryPtr += outputStructureSize; *BytesRequired = newBytesRequired; *EntriesFilled += 1; } else { invalidEntries++; currentInEntryPtr += inputStructureSize; outputStringLocation = oldStringLocation; } } cleanup: if ( InvalidEntries != NULL ) { *InvalidEntries = invalidEntries; } return; } // XsFillEnumBuffer LPBYTE XsFindParameters ( IN LPTRANSACTION Transaction ) /*++ Routine Description: This routine finds the start of the parameters section in the transaction block of a remote down-level API request. Arguments: Transaction - a pointer to a transaction block containing information about the API to process. Return Value: None. --*/ { LPBYTE s; // // Skip over the API number and parameters description string. // for ( s = Transaction->InParameters + 2; *s != '\0'; s++ ); // // Skip over the zero terminator and the data description string. // for ( s++; *s != '\0'; s++ ); // // Return a pointer to the location after the zero terminator. // return s + 1; } // XsFindParameters WORD XsPackReturnData ( IN LPVOID Buffer, IN WORD BufferLength, IN LPDESC Descriptor, IN DWORD EntriesRead ) /*++ Routine Description: This routine, called by get info and enum API handlers, packs the output data so that no unused data is returned to the client. This is necessary because buffers are filled with variable-length data starting at the end, thereby leaving potentially large gaps of unused space between the end of fixed structures and the beginning of variable-length data. Arguments: Buffer - a pointer to the buffer to pack. BufferLength - the length of this buffer. Descriptor - a pointer to a string which describes the fixed structures in the buffer. EntriesRead - the count of fixed structures in the buffer. Return Value: WORD - the "converter word" which informs the client how much to adjust pointers in the fixed structures so that they are meaningful. --*/ { DWORD structureSize; LPBYTE lastFixedStructure; LPBYTE endOfFixedStructures; DWORD lastPointerOffset; DWORD beginningOfVariableData; // // If there is no data, return immediately. // if ( EntriesRead == 0 ) { return 0; } // // Find the size of a single fixed-length structure. // structureSize = RapStructureSize( Descriptor, Response, FALSE ); // // Use this and the number of entries to find the location of the // last fixed structure and where the fixed structures end. // endOfFixedStructures = (LPBYTE)Buffer + EntriesRead * structureSize; lastFixedStructure = endOfFixedStructures - structureSize; // // Find the offset into the fixed structure of the last pointer // to variable data. The value stored at this offset in the last // structure is the offset to the first variable data. // lastPointerOffset = RapLastPointerOffset( Descriptor, Response, FALSE ); // // If there are no pointers, there is obviously no data to pack. // if ( lastPointerOffset == NO_POINTER_IN_STRUCTURE ) { return 0; } beginningOfVariableData = SmbGetUlong( (LPDWORD)(lastFixedStructure + lastPointerOffset) ); // // If this offset is NULL, then the data overflowed, hence the buffer // is nearly full. Don't do any packing. // // Also, if the gap is less than MAXIMUM_ALLOWABLE_DATA_GAP then it // isn't worth doing the packing because of the time involved in // the data copy. // if ( beginningOfVariableData == (DWORD)0 || (DWORD_PTR)Buffer + beginningOfVariableData - (DWORD_PTR)endOfFixedStructures <= MAXIMUM_ALLOWABLE_DATA_GAP ) { return 0; } // // Move the variable data up to follow the fixed structures. // RtlMoveMemory( endOfFixedStructures, (LPBYTE)Buffer + beginningOfVariableData, BufferLength - beginningOfVariableData ); // // Return the distance we moved the variable data. // return (WORD)( (DWORD_PTR)Buffer + beginningOfVariableData - (DWORD_PTR)endOfFixedStructures ); } // XsPackReturnData VOID XsSetDataCount( IN OUT LPWORD DataCount, IN LPDESC Descriptor, IN WORD Converter, IN DWORD EntriesRead, IN WORD ReturnStatus ) /*++ Routine Description: This routine calculates the return data count based on a number of characteristics of the return data. This routine will examine the buffer size, the number of entries placed in the buffer, whether the data was packed, and what the return code was to determine the return data size. The following assumptions are made about the data: only calls with ReturnCode = NERR_Success or ERROR_MORE_DATA return any data to the client; and if there is no pointer in the fixed entries, then there is no variable data. Handlers which cannot assure these two assumptions must determine the data count manually. Arguments: DataCount - a pointer to a short word indicating the maximum return data count (usually the BufLen parameter). On return, this word will hold the actual return data count. Descriptor - a string describing the structure of the fixed entries in the buffer. Converter - The adjustment value for pointers in data. A non-zero value indicates data in the buffer is packed. EntriesRead - Number of entries placed in the buffer. Used to determine data count for buffers with no variable data. ReturnStatus - Return status of the API call, as it will be returned to the client (in other words, converted to a WORD). Return Value: None. --*/ { if (( ReturnStatus != NERR_Success ) && ( ReturnStatus != ERROR_MORE_DATA)) { // // If the return status is not NERR_Success or ERROR_MORE_DATA, then // the return data count is 0. SmbPutUshort( DataCount, 0 ); return; } if ( RapLastPointerOffset( Descriptor, Response, FALSE ) == NO_POINTER_IN_STRUCTURE ) { // // If there is no variable data, the return data count is the size // of the fixed structures. SmbPutUshort( DataCount, (WORD)(RapStructureSize( Descriptor, Response, FALSE ) * EntriesRead )); return; } SmbPutUshort( DataCount, SmbGetUshort( DataCount ) - Converter ); return; } // XsSetDataCount VOID XsSetParameters ( IN LPTRANSACTION Transaction, IN LPXS_PARAMETER_HEADER Header, IN LPVOID Parameters ) /*++ Routine Description: This routine takes parameters from the structure allocated by XsCaptureParameters and uses the descriptor string to place them in the correct format in the transaction block. It also frees the buffer holding the parameter structure. Arguments: Transaction - a pointer to the transaction block describing the request. Header - a pointer to the parameter header, which contains information from the API handler such as the converter word and return status. Parameters - a pointer to the parameter structure. Return Value: None. --*/ { LPBYTE inParams = Parameters; LPBYTE outParams = Transaction->OutParameters; LPDESC descriptorString; LPDESC descriptor; LPBYTE outParamsMax = outParams + Transaction->MaxParameterCount; // // The first two bytes of the parameter section are the API number, // then comes the descriptor string. // descriptorString = Transaction->InParameters + 2; // // Set up the first part of the output parameters from the parameter // header. // if( outParams + sizeof(WORD) > outParamsMax ) goto insuff_buffer; SmbPutUshort( (LPWORD)outParams, Header->Status ); outParams += sizeof(WORD); if( outParams + sizeof(WORD) > outParamsMax ) goto insuff_buffer; SmbPutUshort( (LPWORD)outParams, Header->Converter ); outParams += sizeof(WORD); // // Initially set the size of the return data to 0. If there is a // receive buffer for this call, the API handler has changed the // buffer length parameter to the count of data returned, which // will be transferred to the DataCount variable later. // Transaction->DataCount = 0; // // Walk through the descriptor string, converting from the total // parameter set to the smaller set passed back to the client. In // general, only information the client does not already know is // passed back as parameters. // for ( descriptor = descriptorString; *descriptor != '\0'; ) { switch ( *descriptor++ ) { case REM_ASCIZ: case REM_NULL_PTR: // // !!! Parameter string descriptors may not have maximum length // counts. // NetpAssert( !isdigit( *descriptor )); // // The parameter is a pointer to a string, which is // not returned to the client. // inParams += sizeof(LPSTR); break; case REM_BYTE_PTR: case REM_FILL_BYTES: // // Array of bytes, doesn't get sent back. // // // Skip over any numeric characters in descriptor. // RapAsciiToDecimal( &descriptor ); inParams += sizeof(LPBYTE); break; case REM_DWORD: // // The parameter is a input word not returned to the client. // // !!! This assumes that an array of dwords will never be passed // as a parameter. NetpAssert( !isdigit( *descriptor )); inParams += sizeof(DWORD); break; case REM_ENTRIES_READ: case REM_RCV_WORD_PTR: // // Count of entries read (e) or receive word pointer (h). // This is an output parameter, so copy over the word. // if( outParams + sizeof(WORD) > outParamsMax ) goto insuff_buffer; SmbPutUshort( (LPWORD)outParams, SmbGetUshort( (LPWORD)inParams ) ); inParams += sizeof(WORD); outParams += sizeof(WORD); break; case REM_RCV_DWORD_PTR: // // Count of receive dword pointer (h). // This is an output parameter, so copy over the word. // if( outParams + sizeof(DWORD) > outParamsMax ) goto insuff_buffer; SmbPutUlong( (LPDWORD)outParams, SmbGetUlong( (LPDWORD)inParams ) ); inParams += sizeof(DWORD); outParams += sizeof(DWORD); break; case REM_RCV_BUF_LEN: // // The length of the receive buffer (r). The parameter is not // returned to the client, but it is used to set the return // data count. // Transaction->DataCount = (DWORD)SmbGetUshort( (LPWORD)inParams ); inParams += sizeof(WORD); break; case REM_RCV_BUF_PTR: case REM_SEND_BUF_PTR: // // A pointer to a data buffer. This is not returned to the // client. // inParams += sizeof(LPBYTE); break; case REM_RCV_BYTE_PTR: { // // The parameter indicates return bytes. // DWORD arraySize; arraySize = sizeof(BYTE) * RapDescArrayLength( descriptor ); if( outParams + arraySize > outParamsMax ) goto insuff_buffer; RtlCopyMemory( outParams, inParams, arraySize ); outParams += arraySize; inParams += arraySize; break; } case REM_SEND_BUF_LEN: case REM_WORD: case REM_PARMNUM: // // The parameter is a input word not returned to the client. // // !!! This assumes that an array of words will never be passed // as a parameter. NetpAssert( !isdigit( *descriptor )); inParams += sizeof(WORD); break; default: IF_DEBUG(ERRORS) { NetpKdPrint(( "XsSetParameters: unsupported character at %lx: %c\n", descriptor - 1, *( descriptor - 1 ))); NetpBreakPoint( ); } } } // // Indicate the number of response parameter bytes. // Transaction->ParameterCount = (DWORD)((DWORD_PTR)outParams - (DWORD_PTR)(Transaction->OutParameters) ); // // Free the parameter buffer allocated by XsCaptureParameters. // NetpMemoryFree( Header ); return; insuff_buffer: Header->Status = NERR_BufTooSmall; return; } // XsSetParameters NET_API_STATUS XsValidateShareName( IN LPSTR ShareName ) /*++ Routine Description: This routine determines whether the supplied string is a valid share name of the format \\computer\share, with both computer name and share name no longer than permitted by LanMan 2.0. It does not attempt to determine whether the share actually exists. Arguments: ShareName - The share name to be validated (an ASCII string) Return Value: NET_API_STATUS - NERR_Success if the share name is valid, ERROR_INVALID_PARAMETER otherwise. --*/ { DWORD componentLength; NET_API_STATUS status = NERR_Success; if ( ShareName == NULL ) { // NULL is OK return NERR_Success; } componentLength = 0; while ( *ShareName == '\\' ) { componentLength++; ShareName++; } if ( componentLength != 2 ) { status = ERROR_INVALID_PARAMETER; goto cleanup; } componentLength = 0; while (( *ShareName != '\\' ) && ( *ShareName != '\0' )) { componentLength++; ShareName++; } if (( *ShareName == '\0' ) || ( componentLength < 1 ) || ( componentLength > MAX_PATH )) { status = ERROR_INVALID_PARAMETER; goto cleanup; } componentLength = 0; while ( *ShareName == '\\' ) { componentLength++; ShareName++; } if ( componentLength != 1 ) { status = ERROR_INVALID_PARAMETER; goto cleanup; } componentLength = 0; while (( *ShareName != '\\' ) && ( *ShareName != '\0' )) { componentLength++; ShareName++; } if (( *ShareName == '\\' ) || ( componentLength < 1 ) || ( componentLength > MAX_PATH )) { status = ERROR_INVALID_PARAMETER; goto cleanup; } cleanup: return status; } VOID SmbCapturePtr( LPBYTE PointerDestination, LPBYTE PointerValue ) /*++ Routine Description: This routine captures a pointer from the supplied buffer and places it into the destination buffer. Arguments: PointerDestination - A pointer to the pointer value destination. PointerSource - A pointer to the pointer value source. Return Value: None. --*/ { XsSmbPutPointer( PointerDestination, PointerValue ); }