You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
444 lines
16 KiB
444 lines
16 KiB
/*++
|
|
|
|
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
|