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

907 lines
27 KiB
C

/*++
Copyright (c) 1991-92 Microsoft Corporation
Module Name:
rxshare.c
Abstract:
Contains down-level remoted RxNetShare routines:
RxNetShareAdd
RxNetShareCheck
RxNetShareDel
RxNetShareEnum
RxNetShareGetInfo
RxNetShareSetInfo
(GetShareInfoDescriptors)
(ConvertMaxUsesField)
Author:
Richard Firth (rfirth) 20-May-1991
Environment:
Win-32/flat address space
Notes:
Routines in this module assume that caller-supplied parameters have
already been verified. No effort is made to further check the veracity
of parms. Any actions causing exceptions must be trapped at a higher
level. This applies to ALL parameters - strings, pointers, buffers, etc.
Revision History:
08-Apr-1992
Try to avoid >1 calls to down-level server for RxNetShareEnum
Fix problem of converting 16-bit numbers >32768 into negative 32-bit
numbers on GetInfo and Enum: 65535 is a special value; everything
else in unsigned 16-bit
01-Apr-1992 JohnRo
Prevent too large size requests.
Use NetApiBufferAllocate() instead of private version.
05-Dec-1991 RFirth
Enum returns in TotalEntries (or EntriesLeft) the number of items to
be enumerated BEFORE this call. Used to be number left after this call
21-Nov-1991 JohnRo
Removed NT dependencies to reduce recompiles.
16-Sep-1991 JohnRo
Use DBGSTATIC for nonexported routines.
13-Sep-1991 JohnRo
Corrected typedef used for descriptors (LPDESC, not LPTSTR).
Made changes suggested by PC-LINT.
20-May-1991 RFirth
Created
--*/
#include "downlevl.h"
#include "rxshare.h"
#include <lmshare.h> // typedefs for SHARE_INFO etc.
#define SHARE_ADD_LEVEL 2 // only level at which we can add stuff down-stream
#define INITIAL_BUFFER_SIZE 4096 // Arbitrary! But can't be integral multiple of infolen
//
// prototypes
//
DBGSTATIC void
GetShareInfoDescriptors(
IN DWORD level,
OUT LPDESC* pDesc16,
OUT LPDESC* pDesc32,
OUT LPDESC* pDescSmb,
OUT LPDWORD pDatasize
);
DBGSTATIC
VOID
ConvertMaxUsesField(
IN LPSHARE_INFO_2 Buffer,
IN DWORD NumberOfLevel2Structures
);
NET_API_STATUS
RxNetShareAdd(
IN LPTSTR ServerName,
IN DWORD Level,
IN LPBYTE Buffer,
OUT LPDWORD ParmError OPTIONAL
)
/*++
Routine Description:
Attempts the NetShareAdd API at the named server. The server supports an
earlier version of LanMan than that under which we are operating so we
have to slightly modify things in order that the down-level server
understands the request
Note: we don't hand back any ParmError information. This level of info
is primarily supplied by the new (NT) rouines
Arguments:
ServerName - at which server to perform this request
Level - of information being supplied. Must Be 2
Buffer - pointer to supplied level 2 share information buffer
ParmError - place to return the id of the parameter causing strife
Return Value:
NET_API_STATUS:
Success = NERR_Success
Failure = ERROR_INVALID_LEVEL
Level must be 2
(return code from RxRemoteApi)
(return code from remoted NetShareAdd API)
--*/
{
UNREFERENCED_PARAMETER(ParmError);
UNREFERENCED_PARAMETER(Level);
if ( Buffer == NULL )
return ERROR_INVALID_PARAMETER;
#if DBG
//
// The ServerName parameter must be a non-NUL(L) string. We know this must
// be so since (presumably) the server name was used as the criteria to get
// here. Ensure that this is so (in the non-release version).
//
NetpAssert(ServerName != NULL);
NetpAssert(*ServerName);
#endif
return RxRemoteApi(API_WShareAdd, // API #
ServerName, // where it will run
REMSmb_NetShareAdd_P, // parameter descriptor
REM16_share_info_2, // Data descriptor/16-bit
REM32_share_info_2, // Data descriptor/32-bit
REMSmb_share_info_2, // Data descriptor/SMB
NULL, // Aux descriptor/16-bit
NULL, // Aux descriptor/32-bit
NULL, // Aux descriptor/SMB
FALSE, // this call needs user to be logged on
SHARE_ADD_LEVEL, // level. Since there's only 1 push immediate
Buffer, // caller's SHARE_INFO_2 struct
//
// we have to supply the size of the buffer - down-level
// expects it, NT doesn't. Defined as the size of the fixed
// structure (ie a SHARE_INFO_2) plus the lengths of all
// the variable fields (all strings in this case)
//
sizeof(SHARE_INFO_2) + // parameter supplied by us
POSSIBLE_STRSIZE(((SHARE_INFO_2*)Buffer)->shi2_netname) +
POSSIBLE_STRSIZE(((SHARE_INFO_2*)Buffer)->shi2_remark) +
POSSIBLE_STRSIZE(((SHARE_INFO_2*)Buffer)->shi2_path) +
POSSIBLE_STRSIZE(((SHARE_INFO_2*)Buffer)->shi2_passwd)
);
}
NET_API_STATUS
RxNetShareCheck(
IN LPTSTR ServerName,
IN LPTSTR DeviceName,
OUT LPDWORD Type
)
/*++
Routine Description:
Attempts to perform the NetShareCheck API on a remote down-level server
Arguments:
ServerName - where this call will happen
DeviceName - the thing we are querying
Type - where we store share type in the (unlikely) event of success
Return Value:
NET_API_STATUS
Success = NERR_Success
Failure =
--*/
{
#if DBG
//
// The ServerName parameter must be a non-NUL(L) string. We know this must
// be so since (presumably) the server name was used as the criteria to get
// here. Ensure that this is so (in the non-release version).
//
NetpAssert(ServerName != NULL);
NetpAssert(*ServerName);
#endif
//
// We have to have something in the device name
// Ensure that the caller provided us with the address of the place he/she
// wants the type info to be left
//
if (!VALID_STRING(DeviceName) || Type == NULL) {
return ERROR_INVALID_PARAMETER;
}
return RxRemoteApi(API_NetShareCheck,
ServerName, // where it will run
REMSmb_NetShareCheck_P, // parameter descriptor
NULL, // Data descriptor/16-bit
NULL, // Data descriptor/32-bit
NULL, // Data descriptor/SMB
NULL, // Aux descriptor/16-bit
NULL, // Aux descriptor/32-bit
NULL, // Aux descriptor/SMB
FALSE, // this call needs user to be logged on
DeviceName, // parm 1
Type // parm 2
);
}
NET_API_STATUS
RxNetShareDel(
IN LPTSTR ServerName,
IN LPTSTR NetName,
IN DWORD Reserved
)
/*++
Routine Description:
Performs the NetShareDel API at a remote down-level server
Arguments:
ServerName - where to perform the request
NetName - to remove
Reserved - MBZ
Return Value:
NET_API_STATUS
Success = NERR_Success
Failure = ERROR_INVALID_PARAMETER
--*/
{
#if DBG
//
// The ServerName parameter must be a non-NUL(L) string. We know this must
// be so since (presumably) the server name was used as the criteria to get
// here. Ensure that this is so (in the non-release version).
//
NetpAssert(ServerName != NULL);
NetpAssert(*ServerName);
#endif
//
// if the NetName parameter is a NULL pointer or string OR the Reserved
// parameter is NOT 0 then return an error
//
if (!VALID_STRING(NetName) || Reserved) {
return ERROR_INVALID_PARAMETER;
}
//
// Just call the RpcXlate routine to perform it and return the result
//
return RxRemoteApi(API_WShareDel,
ServerName, // where it will run
REMSmb_NetShareDel_P, // parameter descriptor
NULL, // Data descriptor/16-bit
NULL, // Data descriptor/32-bit
NULL, // Data descriptor/SMB
NULL, // Aux descriptor/16-bit
NULL, // Aux descriptor/32-bit
NULL, // Aux descriptor/SMB
FALSE, // this call needs user to be logged on
NetName, // parm 1
0 // parm 2 (RESERVED - MBZ)
);
}
NET_API_STATUS
RxNetShareEnum(
IN LPTSTR ServerName,
IN DWORD Level,
OUT LPBYTE* Buffer,
IN DWORD PrefMaxLen,
OUT LPDWORD EntriesRead,
OUT LPDWORD EntriesLeft,
IN OUT LPDWORD ResumeHandle OPTIONAL
)
/*++
Routine Description:
Performs NetShareEnum API at a remote down-level server. Any returned info
will be in 32-bit LanMan format. Information returned in buffer sourced by
this routine. Caller must use NetApiBufferFree when returned buffer no
longer required
Arguments:
ServerName - where to perform the request
Level - of info to return. Can be 0, 1 or 2
Buffer - pointer to pointer to returned info buffer
PrefMaxLen - caller preferred maximum size of returned buffer
EntriesRead - pointer to number of entries being returned from this call
EntriesLeft - pointer to total number of share info structures which could be returned
ResumeHandle- NOT Allowed on down level versions. Must Be NULL
Return Value:
NET_API_STATUS
Success = NERR_Success
Failure = ERROR_INVALID_LEVEL
Level parameter not in range 0 <= Level <= 2
ERROR_INVALID_PARAMETER
Non-NULL ResumeHandle. ResumeHandle can be NULL or a
pointer to 0
(return code from NetApiBufferAllocate)
(return code from RxRemoteApi)
--*/
{
NET_API_STATUS rc;
DWORD array_size;
LPDESC pDesc16;
LPDESC pDesc32;
LPDESC pDescSmb;
LPBYTE ourbuf;
DWORD infolen;
DWORD entries_read, total_avail;
UNREFERENCED_PARAMETER(PrefMaxLen);
#if DBG
//
// The ServerName parameter must be a non-NUL(L) string. We know this must
// be so since (presumably) the server name was used as the criteria to get
// here. Ensure that this is so (in the non-release version).
//
NetpAssert(ServerName != NULL);
NetpAssert(*ServerName);
#endif
//
// Set the number of entries read and total available to sensible defaults.
// Side effect of testing writability of supplied parameters
//
//
// I assume that:
// Buffer is a valid, non-NULL pointer
// EntriesRead is a valid, non-NULL pointer
// EntriesLeft is a valid, non-NULL pointer
// since these should have been verified at the API level
//
*Buffer = NULL;
*EntriesRead = 0;
*EntriesLeft = 0;
//
// Check for invalid parameters.
// NB Does Assume that DWORD is unsigned
// Ensure that:
// Level is not >2
// ResumeHandle is NULL or a pointer to NULL
//
if ((ResumeHandle != NULL) && *ResumeHandle) {
return ERROR_INVALID_PARAMETER;
}
if (Level > 2) {
return ERROR_INVALID_LEVEL;
}
//
// Decide which descriptors to use, based on the Level parameter
//
GetShareInfoDescriptors(Level, &pDesc16, &pDesc32, &pDescSmb, &infolen);
ourbuf = NULL;
//
// here we used to let RxRemoteApi allocate a buffer (64K intermediate)
// and do the transaction, returning us a buffer just large enough to
// hold the returned information. WinBall server barfs if it gets a
// request with a 64K buffer, so we have to solicit size info until we
// get everything back. Unfortunately - as of writing - we have no way
// of knowing the type of server we will make the transaction request to
// so we may end up having to make >1 request to a LM 2.1 server where
// we used to be able to get away with 1. On the other hand we can't risk
// upsetting the WB server. Compromise time. Send a 'reasonable' sized
// request to the other side (4K buffer). If it isn't sufficient then
// we loop again, allocating the required buffer
//
//
// what about a LRU cache which keeps the size of the buffer required
// to satisfy an enum request to a particular down-level server?
//
//
// Loop until we have enough memory or we die for some other reason.
//
array_size = INITIAL_BUFFER_SIZE;
do {
// Figure out how much memory we need.
//
// Remote the API, which will allocate the array for us.
//
rc = RxRemoteApi(API_WShareEnum,
ServerName, // where it will run
REMSmb_NetShareEnum_P, // parameter descriptor
pDesc16, // Data descriptor/16-bit
pDesc32, // Data descriptor/32-bit
pDescSmb, // Data descriptor/SMB
NULL, // Aux descriptor/16-bit
NULL, // Aux descriptor/32-bit
NULL, // Aux descriptor/SMB
ALLOCATE_RESPONSE, // allocate a buffer for us
Level, // level parameter
&ourbuf, // pointer to allocated buffer
array_size, // size of down-level buffer
&entries_read, // pointer to entries read variable
&total_avail // pointer to total entries variable
);
if (rc == ERROR_MORE_DATA) {
(void) NetApiBufferFree( ourbuf );
ourbuf = NULL;
if (array_size >= MAX_TRANSACT_RET_DATA_SIZE) {
//
// No point in trying with a larger buffer
//
break;
}
#if DBG
NetpAssert(array_size != total_avail * infolen);
#endif
array_size = (total_avail * infolen);
if (array_size > MAX_TRANSACT_RET_DATA_SIZE) {
//
// Try once more with the maximum-size buffer
//
array_size = MAX_TRANSACT_RET_DATA_SIZE;
}
#if DBG
NetpAssert( array_size != 0 );
#endif
}
} while (rc == ERROR_MORE_DATA);
//
// if we met with an error then free the allocated buffer and return the
// error to the caller. If there was no error then we return the items
// received from the down-level server
//
if (rc) {
if (ourbuf != NULL) {
(void) NetApiBufferFree(ourbuf);
}
} else {
if (Level == 2) {
ConvertMaxUsesField((LPSHARE_INFO_2)ourbuf, entries_read);
}
*Buffer = ourbuf;
*EntriesRead = entries_read;
*EntriesLeft = total_avail;
}
return rc;
}
NET_API_STATUS
RxNetShareGetInfo(
IN LPTSTR ServerName,
IN LPTSTR NetName,
IN DWORD Level,
OUT LPBYTE* Buffer
)
/*++
Routine Description:
Performs the NetShareGetInfo API at a remote down-level server. The returned
information will be in 32-bit LanMan format. Returns single information
structure in a buffer sourced in this routine. Caller must use
NetApiBufferFree when finished with buffer
Arguments:
ServerName - where to perform the request
NetName - name of thing to get information about
Level - level of information requested - 0, 1, 2 are valid
Buffer - pointer to pointer to returned buffer
Return Value:
NET_API_STATUS
Success = NERR_Success
Failure = ERROR_INVALID_LEVEL
ERROR_INVALID_PARAMETER
(return code from NetApiBufferAllocate)
(return code from RxRemoteApi)
--*/
{
NET_API_STATUS rc;
LPDESC pDesc16; // pointer to 16-bit info descriptor for RxRemoteApi
LPDESC pDesc32; // pointer to 32-bit info descriptor for RxRemoteApi
LPDESC pDescSmb; // pointer to SMB info descriptor for RxRemoteApi
LPBYTE ourbuf; // buffer we allocate, fill, and give to the caller
DWORD total_avail; // 32-bit total available if supplied buffer too small
DWORD infolen; // 32-bit place to store size of required buffer
#if DBG
//
// The ServerName parameter must be a non-NUL(L) string. We know this must
// be so since (presumably) the server name was used as the criteria to get
// here. Ensure that this is so (in the non-release version).
//
NetpAssert(ServerName != NULL);
NetpAssert(*ServerName);
#endif
//
// Preset Buffer and check it is valid pointer
//
*Buffer = NULL;
//
// Perform parameter validity checks:
// Level must be in range 0 <= Level <= 2
// NetName must be non-NULL pointer to non-NULL string
// Buffer must be non-NULL pointer
// NB. Assumes DWORD is unsigned quantity
//
if (Level > 2) {
return ERROR_INVALID_LEVEL;
}
if (!VALID_STRING(NetName) || !Buffer) {
return ERROR_INVALID_PARAMETER;
}
//
// Work out the descriptor and buffer size requirements based on the
// requested level
//
GetShareInfoDescriptors(Level, &pDesc16, &pDesc32, &pDescSmb, &infolen);
//
// allocate a buffer size required to fit in 1 structure at info level
// requested. If the allocation fails then return the error
// We have to allocate space for the strings too, don't forget
//
ourbuf = NULL;
rc = RxRemoteApi(API_WShareGetInfo,
ServerName, // where it will happen
REMSmb_NetShareGetInfo_P, // parameter descriptor
pDesc16, // Data descriptor/16-bit
pDesc32, // Data descriptor/32-bit
pDescSmb, // Data descriptor/SMB
NULL, // Aux descriptor/16-bit
NULL, // Aux descriptor/32-bit
NULL, // Aux descriptor/SMB
ALLOCATE_RESPONSE, // allocate a buffer for us
NetName, // pointer to thing to get info on
Level, // level of info
&ourbuf, // pointer to buffer sourced by us
infolen, // size of our sourced buffer
&total_avail // pointer to total available
);
//
// If the remote NetShareGetInfo call succeeded then give the returned
// buffer to the caller
//
if (rc == NERR_Success) {
if (Level == 2) {
ConvertMaxUsesField((LPSHARE_INFO_2)ourbuf, 1);
}
*Buffer = ourbuf;
} else if (ourbuf) {
//
// if we didn't record a success then free the buffer we previously allocated
//
(void) NetApiBufferFree(ourbuf);
}
return rc;
}
NET_API_STATUS
RxNetShareSetInfo(
IN LPTSTR ServerName,
IN LPTSTR NetName,
IN DWORD Level,
IN LPBYTE Buffer,
OUT LPDWORD ParmError OPTIONAL
)
/*++
Routine Description:
Performs the NetShareSetInfo API at a remote down-level server
Arguments:
ServerName - where to perform the request
NetName - name of thing for which to set info
Level - level of information - 0, 1, 2, 1004, 1005, 1006, 1009
Buffer - buffer containing info at defined level
ParmError - pointer to invalid parameter ordinal
Return Value:
NET_API_STATUS
Success = NERR_Success
Failure = ERROR_INVALID_LEVEL
ERROR_INVALID_PARAMETER
(return code from RxRemoteApi)
--*/
{
DWORD infolen; // size of structure
DWORD parmnum; // we have to cobble down-level parmnum from Level
LPDESC pDesc16; // used in call to GetShareInfoDescriptors
LPDESC pDesc32; // ditto. Only interested in length of info structure
LPDESC pDescSmb; // ditto. Only interested in length of info structure
UNREFERENCED_PARAMETER(ParmError);
#if DBG
//
// The ServerName parameter must be a non-NUL(L) string. We know this must
// be so since (presumably) the server name was used as the criteria to get
// here. Ensure that this is so (in the non-release version).
//
NetpAssert(ServerName != NULL);
NetpAssert(*ServerName);
#endif
//
// Perform parameter validity checks:
// NetName must be non-NULL pointer to non-NULL string
// Buffer must be non-NULL pointer to non-NULL pointer
// Level must be in range
// NB. Assumes that DWORD is unsigned!
//
if (!VALID_STRING(NetName) || !Buffer) {
return ERROR_INVALID_PARAMETER;
}
if (Level < 1 || (Level > 2 && (Level < 1004 || (Level > 1006 && Level != 1009)))) {
return ERROR_INVALID_LEVEL;
}
//
// We can set individual info fields using the levels > 1000. We have to
// create level and parmnum info for down-level
//
if (Level > 2) {
//
// Individual fields are indicated by the old (down-level) parmnum,
// augmented by 1000. Split level and parmnum parameters
//
parmnum = Level - PARMNUM_BASE_INFOLEVEL;
Level = 2;
pDesc16 = REM16_share_info_2_setinfo;
pDesc32 = REM32_share_info_2_setinfo;
pDescSmb = REMSmb_share_info_2_setinfo;
switch (parmnum) {
case 4: // remark
case 9: // password
infolen = STRSIZE( (LPTSTR)Buffer );
break;
case 5: // permissions
case 6: // max uses
infolen = sizeof(WORD);
break;
}
} else {
//
// let GetShareInfoDescriptors give us the size of the buffer
// that NetShareSetInfo thinks its getting. We have no other way of
// determining this (have we?). Levels 0 - 2 set the entire structure
//
GetShareInfoDescriptors(Level, &pDesc16, &pDesc32, &pDescSmb, &infolen);
parmnum = PARMNUM_ALL;
}
return RxRemoteApi(API_WShareSetInfo,
ServerName, // where it will run
REMSmb_NetShareSetInfo_P, // parameter descriptor
pDesc16, // Data descriptor/16-bit
pDesc32, // Data descriptor/32-bit
pDescSmb, // Data descriptor/SMB
NULL, // Aux descriptor/16-bit
NULL, // Aux descriptor/32-bit
NULL, // Aux descriptor/SMB
FALSE, // this call needs user to be logged on
NetName, // pointer to thing to set info on
Level, // level of info
Buffer, // pointer to buffer sourced by caller
infolen, // size of our buffer
//
// in this case, the field index and parm num are the
// same value
//
MAKE_PARMNUM_PAIR(parmnum, parmnum) // what we're setting
);
}
DBGSTATIC void
GetShareInfoDescriptors(
DWORD level,
LPDESC* pDesc16,
LPDESC* pDesc32,
LPDESC* pDescSmb,
LPDWORD pDataSize
)
/*++
Routine Description:
A routinette to return pointers to the 16- and 32-bit share info
structure descriptor strings for each level (0, 1, 2). Also returns
the size required for a returned 16-bit structure converted to 32-bit data
Arguments:
level - of information to be returned
pDesc16 - pointer to returned 16-bit descriptor string
pDesc32 - pointer to returned 32-bit descriptor string
pDescSmb - pointer to returned SMB descriptor string
pDataSize - pointer to returned size of 16-bit structure
Return Value:
None.
--*/
{
switch (level) {
case 0:
*pDesc16 = REM16_share_info_0;
*pDesc32 = REM32_share_info_0;
*pDescSmb = REMSmb_share_info_0;
*pDataSize = DWORD_ROUNDUP(sizeof(SHARE_INFO_0) // structure size
+ LM20_NNLEN + 1); // + shi0_netname len
break;
case 1:
*pDesc16 = REM16_share_info_1;
*pDesc32 = REM32_share_info_1;
*pDescSmb = REMSmb_share_info_1;
*pDataSize = DWORD_ROUNDUP(sizeof(SHARE_INFO_1) // structure size
+ LM20_NNLEN + 1 // + shi1_netname len
+ LM20_MAXCOMMENTSZ + 1); // + shi1_remark len
break;
case 2:
*pDesc16 = REM16_share_info_2;
*pDesc32 = REM32_share_info_2;
*pDescSmb = REMSmb_share_info_2;
*pDataSize = DWORD_ROUNDUP(sizeof(SHARE_INFO_2) // structure size
+ LM20_NNLEN + 1 // + shi2_netname len
+ LM20_MAXCOMMENTSZ + 1 // + shi2_remark len
+ LM20_PATHLEN + 1 // + shi2_path len
+ SHPWLEN + 1); // + shi2_passwd len
break;
#if DBG
//
// just to be completely paranoid...
//
default:
NetpKdPrint(("%s.%u Unknown Level parameter: %u\n", __FILE__, __LINE__, level));
#endif
}
#if DBG
NetpAssert(INITIAL_BUFFER_SIZE % *pDataSize);
#endif
}
DBGSTATIC
VOID
ConvertMaxUsesField(
IN LPSHARE_INFO_2 Buffer,
IN DWORD NumberOfLevel2Structures
)
/*++
Routine Description:
Given a buffer containing 1 or more SHARE_INFO_2 structures, converts the
shi2_max_uses field to a sensible value. The underlying RAP code converts
the 16-bit number as a signed value, such that 32768 => -32768L. 65535 is
the only 16-bit value which should be sign-extended. Everything else
should be represented as the same number in 32-bits
Arguments:
Buffer - pointer to list of SHARE_INFO_2 structures
NumberOfLevel2Structures - how many structures in list
Return Value:
None.
--*/
{
while (NumberOfLevel2Structures--) {
if (Buffer->shi2_max_uses != -1L) {
Buffer->shi2_max_uses &= 0xffffL;
}
++Buffer;
}
}