/*++ Copyright (c) 1987-92 Microsoft Corporation Module Name: Transact.c Abstract: RxpTransactSmb (analogous to the LanMan 2.x transact routine) performs a transaction FSCTL to the redirector. Author: John Rogers (JohnRo) 01-Apr-1991 (NT version only) Environment: Only runs under NT, although the interface is portable (Win/32). Requires ANSI C extensions: slash-slash comments, long external names. Revision History: various Original code (from LanMan 2.x). 01-Apr-91 JohnRo Converted code from LanMan (OS/2) to NT. 02-Apr-1991 JohnRo Moved NetpRdrFsControlTree to . 17-Apr-1991 JohnRo Fixed memory leaks (especially with pipe name). Quiet debug output by default. Reduced recompile hits from header files. 03-May-1991 JohnRo Pass UNC server name for ease of use. Use Unicode transitional types. Use UNREFERENCED_PARAMETER() macro. 15-May-1991 JohnRo Use FORMAT_LPVOID instead of FORMAT_POINTER, for maximum portability. 22-May-1991 JohnRo Use correct string handling functions to allow UNICODE. Use NetpDbgReasonable(). 14-Jul-1991 JohnRo Don't do assert on server name. 17-Jul-1991 JohnRo Extracted RxpDebug.h from Rxp.h. 04-Oct-1991 JohnRo Generate NERR_BadTransactConfig when IPC$ isn't shared. Clarified a debug output message. Use TEXT() macro. 01-Nov-1991 JohnRo Don't let the new (paranoid) RxpFatalErrorCode() prevent debug output. 16-Jan-1992 JohnRo The redirector always expects UNICODE for the transact parm name. 31-Mar-1992 JohnRo Prevent too large size requests. 22-Sep-1992 JohnRo RAID 6739: Browser too slow when not logged into browsed domain. --*/ // These must be included first: #include // Needed by netlibnt.h. #include // RpcXlate's private header file. // These may be included in any order: #include // REM_APITXT, APIEXTR. #include // NERR_ and ERROR_ equates. #include // NetpIsComputerNameValid(). #include // NetpAssert(), NetpKdPrint(()), FORMAT_ equates. #include // NetpMoveMemory(), etc. #include // TRANSACTION_REQUEST, etc. #include // PREFIX_ equates. #include // IF_DEBUG(). #include // STRCAT(), STRCPY(), STRLEN(). #include #ifdef CDEBUG #include // API_WServerGetInfo, etc. #include // NetpPackString(). #include // SmbGetUshort(). #include // SERVER_INFO_100. #endif // CDEBUG #include // NetpRdrFsControlTree(). NET_API_STATUS RxpTransactSmb( IN LPTSTR UncServerName, IN LPTSTR TransportName OPTIONAL, IN LPVOID SendParmPtr, IN DWORD SendParmLen, IN LPVOID SendDataPtr OPTIONAL, IN DWORD SendDataLen, OUT LPVOID RetParmPtr OPTIONAL, IN DWORD RetParmLen, OUT LPVOID RetDataPtr OPTIONAL, IN OUT LPDWORD RetDataLen, IN BOOL NoPermissionRequired ) /*++ Routine Description: RxpTransactSmb takes the caller's parameters and builds a transaction SMB which is sent to a remote machine. This routine waits for the response to this SMB and returns the status from it. Arguments: UncServerName - Server name to transact with (including \\). SendParmPtr - Pointer to send parameters. SendParmLen - Length of send parameters. SendDataPtr - Optional pointer to send data. SendDataLen - Send data length. RetParmPtr - Optional pointer to buffer for return parameters. RetParmLen - Expected length of return parameters. RetDataPtr - Optional pointer to buffer for return data. RetDataLen - IN: Expected length of return data. OUT: Received length of return data. NoPermissionRequired - TRUE if this is a no permission required API. (I.e. TRUE if the null session may be used.) Return Value: (various values as returned by the remote API, plus values which can be generated by this routine) --*/ /* * Note 1: how the packet is build and sized. * * The paramater buffer for the transaction consists of the * transaction parameter structure, followed by the name of the * target pipe and the password, which is always NULL. The pipe * name and password are ASCIZ strings. * * We build the pipe by taking the canonicalized server name, and * appending the text REM_APITXT (see net/inc/apiworke.h). This text * contains the pipe suffix (\pipe\lanman) plus TWO nulls, one to * terminate the pipe name and one to terminate the (empty) password. * * So, the maximum buffer size is as shown below for the allocation * of ioctl_buf. UNCLEN is the max len of the canonicalized * UncServerName and includes the two leading slashes, but not any * terminating NUL. The terminating NUL, as well as the pipe suffix * and the emptry password, are accounted for in APIEXTR. * * Our actual size is the same, except substitute the length of the * canonicalized UncServerName for UNCLEN. This is how ParmRktLen is * calculated. * */ { #ifndef CDEBUG PLMR_TRANSACTION FsctlParms; // Parms to tell redir what to do. DWORD FsctlParmSize; // Size of FsctlParms and strings. LPTSTR TreeConnName; // LM-style server & share name. #endif // ndef CDEBUG NET_API_STATUS Status; // // MOD 06/11/91 RLF // Create DWORD variable to avoid indirection every time RetDataLen accessed // DWORD InputRetDataLen = *RetDataLen; // // MOD 06/11/91 RLF // IF_DEBUG(TRANSACT) { NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: entered, servername='" FORMAT_LPTSTR "'...\n", UncServerName)); NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: SendParm at " FORMAT_LPVOID ", len=" FORMAT_DWORD " (partial):\n", (LPVOID) SendParmPtr, SendParmLen)); if (SendParmPtr != NULL) { NetpDbgHexDump(SendParmPtr, NetpDbgReasonable(SendParmLen)); } NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: SendData at " FORMAT_LPVOID ", len=" FORMAT_DWORD " (partial):\n", (LPVOID) SendDataPtr, SendDataLen)); if (SendDataPtr != NULL) { NetpDbgHexDump(SendDataPtr, NetpDbgReasonable(SendDataLen)); } NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: RetParmPtr at " FORMAT_LPVOID ", len=" FORMAT_DWORD ".\n", (LPVOID) RetParmPtr, RetParmLen)); NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: (old) RetData at " FORMAT_LPVOID ", " "len=" FORMAT_DWORD " (partial):\n", (LPVOID) RetDataPtr, InputRetDataLen)); if (RetDataPtr != NULL) { NetpDbgHexDump(RetDataPtr, NetpDbgReasonable(InputRetDataLen)); } } NetpAssert( SendParmLen <= MAX_TRANSACT_SEND_PARM_SIZE ); NetpAssert( SendDataLen <= MAX_TRANSACT_SEND_DATA_SIZE ); NetpAssert( RetParmLen <= MAX_TRANSACT_RET_PARM_SIZE ); NetpAssert( InputRetDataLen <= MAX_TRANSACT_RET_DATA_SIZE ); // Assumes that isremote(UncServerName) has already checked for // a NULL and empty string. if ((UncServerName == NULL) || (UncServerName[0] == 0)) { NetpBreakPoint(); return (NERR_InternalError); } if (! NetpIsUncComputerNameValid(UncServerName)) { return (NERR_InvalidComputer); } IF_DEBUG(TRANSACT) { NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: pipe name is '" FORMAT_LPWSTR "'.\n", REM_APITXT)); } #ifndef CDEBUG // // Build NT-style name for what we're connecting to. Note that there is // NOT a pair of backslashes anywhere in this name. // { DWORD NameSize = // /Device/LanManRedirector /server /IPC$\0 ( strlen(DD_NFS_DEVICE_NAME) + STRLEN(UncServerName)-1 + 6 ) * sizeof(TCHAR); TreeConnName = NetpMemoryAllocate( NameSize ); } if (TreeConnName == NULL) { return (ERROR_NOT_ENOUGH_MEMORY); } // // Build the tree connect name. // (void) STRCPY(TreeConnName, UncServerName); // copy "\\server", (void) STRCAT(TreeConnName, (LPTSTR) TEXT("\\IPC$")); // then "\share". IF_DEBUG(TRANSACT) { NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: TreeConnName is '" FORMAT_LPTSTR "'.\n", TreeConnName)); } // Set FsctlParmSize and allocate fsctl structure. FsctlParmSize = sizeof(LMR_TRANSACTION) + (APIEXTR); FsctlParms = NetpMemoryAllocate(FsctlParmSize); if (FsctlParms == NULL) { NetpMemoryFree(TreeConnName); return (ERROR_NOT_ENOUGH_MEMORY); } IF_DEBUG(TRANSACT) { NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: allocated " FORMAT_DWORD " bytes for fsctl parms at " FORMAT_LPVOID ".\n", FsctlParmSize, (LPVOID) FsctlParms)); } FsctlParms->Type = TRANSACTION_REQUEST; FsctlParms->Size = FsctlParmSize; FsctlParms->Version = TRANSACTION_VERSION; FsctlParms->NameLength = APIEXTR-sizeof(WCHAR); FsctlParms->NameOffset = sizeof(LMR_TRANSACTION); NetpMoveMemory( NetpPointerPlusSomeBytes( FsctlParms, sizeof(LMR_TRANSACTION)), // dest REM_APITXT, // src (always UNICODE) APIEXTR-sizeof(WCHAR)); // len (don't copy null) FsctlParms->ResponseExpected = TRUE; FsctlParms->Timeout = REM_API_TIMEOUT; // Timeout time in milliseconds. FsctlParms->SetupWords = 0; FsctlParms->SetupOffset = 0; FsctlParms->MaxSetup = 0; FsctlParms->ParmLength = SendParmLen; FsctlParms->ParmPtr = SendParmPtr; FsctlParms->MaxRetParmLength = RetParmLen; NetpAssert(SendParmPtr == RetParmPtr); FsctlParms->DataLength = SendDataLen; FsctlParms->DataPtr = SendDataPtr; FsctlParms->MaxRetDataLength = InputRetDataLen; FsctlParms->RetDataPtr = RetDataPtr; // // Do the FSCTL! // Status = NetpRdrFsControlTree( TreeConnName, // tree connect name TransportName, // Transport name. USE_IPC, // Connection type FSCTL_LMR_TRANSACT, // fsctl function code NULL, // security descriptor FsctlParms, // input buffer FsctlParmSize, // input buffer length FsctlParms, // output buffer FsctlParmSize, // output buffer length NoPermissionRequired); if (Status == ERROR_BAD_NET_NAME) { Status = NERR_BadTransactConfig; } if (RxpFatalErrorCode(Status)) { IF_DEBUG(TRANSACT) { NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: returning fatal status=" FORMAT_API_STATUS ".\n", Status)); } NetpMemoryFree(FsctlParms); NetpMemoryFree(TreeConnName); return (Status); } // // MOD 06/11/91 RLF // Return the received data length in *RetDataLen // *RetDataLen = FsctlParms->MaxRetDataLength; NetpAssert( *RetDataLen <= MAX_TRANSACT_RET_DATA_SIZE ); // // MOD 06/11/91 RLF // NetpMemoryFree(FsctlParms); NetpMemoryFree(TreeConnName); #else // def CDEBUG { DWORD ApiNumber; ApiNumber = (DWORD) SmbGetUshort((LPWORD) SendParmPtr); IF_DEBUG(TRANSACT) { NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: pretending success for API " FORMAT_DWORD ".\n", ApiNumber)); } SmbPutUshort((LPWORD) RetParmPtr, (WORD) NERR_Success); switch (ApiNumber) { case API_NetRemoteTOD : { UCHAR BogusTime[] = { 0xD0, 0xAE, 0xB2, 0x28, // 21-Aug-1991 (6:20PM) 0x44, 0x33, 0x22, 0x11, // msec (anything) 3, // hours 30, // minutes 15, // seconds 55, // hundredths of seconds 0xFF, 0xFF, // timezone (unknown) 0xA6, 0x00, // clock interval (60 Hz) 10, // day 1, // month 0xC7, 0x07, // year 4}; // weekday NetpAssert(RetDataPtr != NULL); NetpAssert(InputRetDataLen != 0); NetpMoveMemory( RetDataPtr, // dest BogusTime, // src (bogus) InputRetDataLen); // len break; } case API_WServerGetInfo : { LPVOID FixedDataEnd = NetpPointerPlusSomeBytes( RetDataPtr, sizeof(SERVER_INFO_100)); LPBYTE LastString = NetpPointerPlusSomeBytes( RetDataPtr, InputRetDataLen); LPSERVER_INFO_100 p = RetDataPtr; NetpAssert(RetDataPtr != NULL); NetpAssert(InputRetDataLen != 0); p->sv100_name = (LPTSTR) TEXT("\\\\bogus\\name"); if (NetpPackString( & p->sv100_name, // in out FixedDataEnd, // in & LastString) == 0) { // in out NetpBreakPoint(); return (NERR_InternalError); } break; } } } #endif // def CDEBUG Status = (DWORD) SmbGetUshort((LPWORD) RetParmPtr); IF_DEBUG(TRANSACT) { NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: returning status=" FORMAT_API_STATUS ".\n", Status)); NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: RetParm at " FORMAT_LPVOID ", len=" FORMAT_DWORD " (partial):\n", (LPVOID) RetParmPtr, RetParmLen)); if (RetParmPtr != NULL) { NetpDbgHexDump(RetParmPtr, NetpDbgReasonable(RetParmLen)); } NetpKdPrint(( PREFIX_NETAPI "RxpTransactSmb: (new) RetData at " FORMAT_LPVOID ", " "len=" FORMAT_DWORD " (partial):\n", (LPVOID) RetDataPtr, InputRetDataLen)); if (RetDataPtr != NULL) { NetpDbgHexDump(RetDataPtr, NetpDbgReasonable(InputRetDataLen)); } } return (Status); } // RxpTransactSmb