windows-nt/Source/XPSP1/NT/ds/netapi/rpcxlate/rxcommon/transact.c
2020-09-26 16:20:57 +08:00

445 lines
15 KiB
C

/*++
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 <netlibnt.h>.
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 <nt.h> // Needed by netlibnt.h.
#include <rxp.h> // RpcXlate's private header file.
// These may be included in any order:
#include <apiworke.h> // REM_APITXT, APIEXTR.
#include <lmerr.h> // NERR_ and ERROR_ equates.
#include <names.h> // NetpIsComputerNameValid().
#include <netdebug.h> // NetpAssert(), NetpKdPrint(()), FORMAT_ equates.
#include <netlib.h> // NetpMoveMemory(), etc.
#include <ntddnfs.h> // TRANSACTION_REQUEST, etc.
#include <prefix.h> // PREFIX_ equates.
#include <rxpdebug.h> // IF_DEBUG().
#include <tstring.h> // STRCAT(), STRCPY(), STRLEN().
#include <lmuse.h>
#ifdef CDEBUG
#include <apinums.h> // API_WServerGetInfo, etc.
#include <netlib.h> // NetpPackString().
#include <smbgtpt.h> // SmbGetUshort().
#include <server.h> // SERVER_INFO_100.
#endif // CDEBUG
#include <netlibnt.h> // 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