1408 lines
38 KiB
C
1408 lines
38 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
wksta.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the worker routines for the NetWksta APIs
|
|||
|
implemented in the Workstation service.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Rita Wong (ritaw) 20-Feb-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
14-May-1992 JohnRo
|
|||
|
Implemented "sticky set info" and registry watch.
|
|||
|
Corrected an info level: 1015 should be 1013.
|
|||
|
--*/
|
|||
|
|
|||
|
#include "wsutil.h"
|
|||
|
#include "wsdevice.h"
|
|||
|
#include "wssec.h"
|
|||
|
#include "wslsa.h"
|
|||
|
#include "wsconfig.h"
|
|||
|
#include "wswksta.h"
|
|||
|
#include <config.h>
|
|||
|
#include <confname.h>
|
|||
|
#include <prefix.h>
|
|||
|
#include "wsregcfg.h" // Registry helpers
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Local function prototypes //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsValidateAndSetWksta(
|
|||
|
IN DWORD Level,
|
|||
|
IN LPBYTE Buffer,
|
|||
|
OUT LPDWORD ErrorParameter OPTIONAL,
|
|||
|
OUT LPDWORD Parmnum
|
|||
|
);
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsGetSystemInfo(
|
|||
|
IN DWORD Level,
|
|||
|
OUT LPBYTE *BufferPointer
|
|||
|
);
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsGetPlatformInfo(
|
|||
|
IN DWORD Level,
|
|||
|
OUT LPBYTE *BufferPointer
|
|||
|
);
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsFillSystemBufferInfo(
|
|||
|
IN DWORD Level,
|
|||
|
IN DWORD NumberOfLoggedOnUsers,
|
|||
|
OUT LPBYTE *OutputBuffer
|
|||
|
);
|
|||
|
|
|||
|
STATIC
|
|||
|
VOID
|
|||
|
WsUpdateRegistryToMatchWksta(
|
|||
|
IN DWORD Level,
|
|||
|
IN LPBYTE Buffer,
|
|||
|
OUT LPDWORD ErrorParameter OPTIONAL
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
NetrWkstaGetInfo(
|
|||
|
IN LPTSTR ServerName OPTIONAL,
|
|||
|
IN DWORD Level,
|
|||
|
OUT LPWKSTA_INFO WkstaInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is the NetWkstaGetInfo entry point in the Workstation
|
|||
|
service. It checks the security access of the caller before returning
|
|||
|
one the information requested which is either system-wide, or redirector
|
|||
|
specific.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - Supplies the name of server to execute this function
|
|||
|
|
|||
|
Level - Supplies the requested level of information.
|
|||
|
|
|||
|
WkstaInfo - Returns a pointer to a buffer which contains the requested
|
|||
|
workstation information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status = NERR_Success;
|
|||
|
LPBYTE Buffer;
|
|||
|
|
|||
|
ACCESS_MASK DesiredAccess;
|
|||
|
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(ServerName);
|
|||
|
|
|||
|
//
|
|||
|
// Determine the desired access based on the specified info level.
|
|||
|
//
|
|||
|
switch (Level) {
|
|||
|
|
|||
|
//
|
|||
|
// Guest access
|
|||
|
//
|
|||
|
case 100:
|
|||
|
DesiredAccess = WKSTA_CONFIG_GUEST_INFO_GET;
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// User access
|
|||
|
//
|
|||
|
case 101:
|
|||
|
DesiredAccess = WKSTA_CONFIG_USER_INFO_GET;
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Admin or operator access
|
|||
|
//
|
|||
|
case 102:
|
|||
|
case 502:
|
|||
|
DesiredAccess = WKSTA_CONFIG_ADMIN_INFO_GET;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
return ERROR_INVALID_LEVEL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Perform access validation on the caller.
|
|||
|
//
|
|||
|
if (NetpAccessCheckAndAudit(
|
|||
|
WORKSTATION_DISPLAY_NAME, // Subsystem name
|
|||
|
(LPTSTR) CONFIG_INFO_OBJECT, // Object type name
|
|||
|
ConfigurationInfoSd, // Security descriptor
|
|||
|
DesiredAccess, // Desired access
|
|||
|
&WsConfigInfoMapping // Generic mapping
|
|||
|
) != NERR_Success) {
|
|||
|
|
|||
|
return ERROR_ACCESS_DENIED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Only allowed to proceed with get info if no one else is setting
|
|||
|
//
|
|||
|
if (! RtlAcquireResourceShared(&WsInfo.ConfigResource, TRUE)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
switch (Level) {
|
|||
|
|
|||
|
//
|
|||
|
// System-wide information
|
|||
|
//
|
|||
|
case 100:
|
|||
|
case 101:
|
|||
|
case 102:
|
|||
|
status = WsGetSystemInfo(Level, &Buffer);
|
|||
|
if (status == NERR_Success) {
|
|||
|
SET_SYSTEM_INFO_POINTER(WkstaInfo, Buffer);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Platform specific information
|
|||
|
//
|
|||
|
case 502:
|
|||
|
status = WsGetPlatformInfo(
|
|||
|
Level,
|
|||
|
(LPBYTE *) &(WkstaInfo->WkstaInfo502)
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// This should have been caught earlier.
|
|||
|
//
|
|||
|
default:
|
|||
|
NetpAssert(FALSE);
|
|||
|
status = ERROR_INVALID_LEVEL;
|
|||
|
}
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
RtlReleaseResource(&WsInfo.ConfigResource);
|
|||
|
return RtlNtStatusToDosError(GetExceptionCode());
|
|||
|
}
|
|||
|
|
|||
|
RtlReleaseResource(&WsInfo.ConfigResource);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
NetrWkstaSetInfo(
|
|||
|
IN LPTSTR ServerName OPTIONAL,
|
|||
|
IN DWORD Level,
|
|||
|
IN LPWKSTA_INFO WkstaInfo,
|
|||
|
OUT LPDWORD ErrorParameter OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is the NetWkstaSetInfo entry point in the Workstation
|
|||
|
service. It checks the security access of the caller to make sure
|
|||
|
that the caller is allowed to set specific workstation information.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - Supplies the name of server to execute this function
|
|||
|
|
|||
|
Level - Supplies the level of information.
|
|||
|
|
|||
|
WkstaInfo - Supplies a pointer to union structure of pointers to
|
|||
|
buffer of fields to set. The level denotes the fields supplied in
|
|||
|
this buffer.
|
|||
|
|
|||
|
ErrorParameter - Returns the identifier to the invalid parameter if
|
|||
|
this function returns ERROR_INVALID_PARAMETER.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
WKSTA_INFO_502 OriginalWksta = WSBUF;
|
|||
|
NET_API_STATUS status = NERR_Success;
|
|||
|
DWORD Parmnum;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(ServerName);
|
|||
|
|
|||
|
//
|
|||
|
// Check for NULL input buffer
|
|||
|
//
|
|||
|
if (WkstaInfo->WkstaInfo502 == NULL) {
|
|||
|
RETURN_INVALID_PARAMETER(ErrorParameter, PARM_ERROR_UNKNOWN);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Only admins can set redirector configurable fields. Validate access.
|
|||
|
//
|
|||
|
if (NetpAccessCheckAndAudit(
|
|||
|
WORKSTATION_DISPLAY_NAME, // Subsystem name
|
|||
|
(LPTSTR) CONFIG_INFO_OBJECT, // Object type name
|
|||
|
ConfigurationInfoSd, // Security descriptor
|
|||
|
WKSTA_CONFIG_INFO_SET, // Desired access
|
|||
|
&WsConfigInfoMapping // Generic mapping
|
|||
|
) != NERR_Success) {
|
|||
|
|
|||
|
return ERROR_ACCESS_DENIED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Serialize write access
|
|||
|
//
|
|||
|
if (! RtlAcquireResourceExclusive(&WsInfo.ConfigResource, TRUE)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
status = WsValidateAndSetWksta(
|
|||
|
Level,
|
|||
|
(LPBYTE) WkstaInfo->WkstaInfo502,
|
|||
|
ErrorParameter,
|
|||
|
&Parmnum
|
|||
|
);
|
|||
|
|
|||
|
if (status != NERR_Success) {
|
|||
|
goto CleanExit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set NT redirector specific fields
|
|||
|
//
|
|||
|
status = WsUpdateRedirToMatchWksta(
|
|||
|
Parmnum,
|
|||
|
ErrorParameter
|
|||
|
);
|
|||
|
|
|||
|
if (status != NERR_Success) {
|
|||
|
goto CleanExit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Make updates "sticky" (update registry to match wksta).
|
|||
|
//
|
|||
|
WsUpdateRegistryToMatchWksta(
|
|||
|
Level,
|
|||
|
(LPBYTE) WkstaInfo->WkstaInfo502,
|
|||
|
ErrorParameter
|
|||
|
);
|
|||
|
|
|||
|
CleanExit:
|
|||
|
if (status != NERR_Success) {
|
|||
|
WSBUF = OriginalWksta;
|
|||
|
}
|
|||
|
RtlReleaseResource(&WsInfo.ConfigResource);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
NetrWkstaTransportEnum(
|
|||
|
IN LPTSTR ServerName OPTIONAL,
|
|||
|
IN OUT LPWKSTA_TRANSPORT_ENUM_STRUCT TransportInfo,
|
|||
|
IN DWORD PreferedMaximumLength,
|
|||
|
OUT LPDWORD TotalEntries,
|
|||
|
IN OUT LPDWORD ResumeHandle OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is the NetWkstaTransportEnum entry point in the
|
|||
|
Workstation service.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - Supplies the name of server to execute this function
|
|||
|
|
|||
|
TransportInfo - This structure supplies the level of information requested,
|
|||
|
returns a pointer to the buffer allocated by the Workstation service
|
|||
|
which contains a sequence of information structure of the specified
|
|||
|
information level, and returns the number of entries read. The buffer
|
|||
|
pointer is set to NULL if return code is not NERR_Success or
|
|||
|
ERROR_MORE_DATA, or if EntriesRead returned is 0. The EntriesRead
|
|||
|
value is only valid if the return code is NERR_Success or
|
|||
|
ERROR_MORE_DATA.
|
|||
|
|
|||
|
PreferedMaximumLength - Supplies the number of bytes of information
|
|||
|
to return in the buffer. If this value is MAXULONG, all available
|
|||
|
information will be returned.
|
|||
|
|
|||
|
TotalEntries - Returns the total number of entries available. This value
|
|||
|
is only valid if the return code is NERR_Success or ERROR_MORE_DATA.
|
|||
|
|
|||
|
ResumeHandle - Supplies a handle to resume the enumeration from where it
|
|||
|
left off the last time through. Returns the resume handle if return
|
|||
|
code is ERROR_MORE_DATA.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
LMR_REQUEST_PACKET Rrp; // Redirector request packet
|
|||
|
DWORD EnumTransportHintSize = 0; // Hint size from redirector
|
|||
|
|
|||
|
LPBYTE Buffer;
|
|||
|
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(ServerName);
|
|||
|
|
|||
|
//
|
|||
|
// Only level 0 is valid
|
|||
|
//
|
|||
|
if (TransportInfo->Level != 0) {
|
|||
|
return ERROR_INVALID_LEVEL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up request packet. Output buffer structure is of enumerate
|
|||
|
// transport type.
|
|||
|
//
|
|||
|
Rrp.Version = REQUEST_PACKET_VERSION;
|
|||
|
Rrp.Type = EnumerateTransports;
|
|||
|
Rrp.Level = TransportInfo->Level;
|
|||
|
Rrp.Parameters.Get.ResumeHandle = (ARGUMENT_PRESENT(ResumeHandle)) ?
|
|||
|
*ResumeHandle : 0;
|
|||
|
|
|||
|
//
|
|||
|
// Get the requested information from the redirector.
|
|||
|
//
|
|||
|
status = WsDeviceControlGetInfo(
|
|||
|
Redirector,
|
|||
|
WsRedirDeviceHandle,
|
|||
|
FSCTL_LMR_ENUMERATE_TRANSPORTS,
|
|||
|
&Rrp,
|
|||
|
sizeof(LMR_REQUEST_PACKET),
|
|||
|
&Buffer,
|
|||
|
PreferedMaximumLength,
|
|||
|
EnumTransportHintSize,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Return output parameters
|
|||
|
//
|
|||
|
if (status == NERR_Success || status == ERROR_MORE_DATA) {
|
|||
|
SET_TRANSPORT_ENUM_POINTER(
|
|||
|
TransportInfo,
|
|||
|
Buffer,
|
|||
|
Rrp.Parameters.Get.EntriesRead
|
|||
|
);
|
|||
|
|
|||
|
if (TransportInfo->WkstaTransportInfo.Level0 == NULL)
|
|||
|
{
|
|||
|
LocalFree(Buffer);
|
|||
|
}
|
|||
|
|
|||
|
*TotalEntries = Rrp.Parameters.Get.TotalEntries;
|
|||
|
|
|||
|
if (status == ERROR_MORE_DATA && ARGUMENT_PRESENT(ResumeHandle)) {
|
|||
|
*ResumeHandle = Rrp.Parameters.Get.ResumeHandle;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
NetrWkstaTransportAdd (
|
|||
|
IN LPTSTR ServerName OPTIONAL,
|
|||
|
IN DWORD Level,
|
|||
|
IN LPWKSTA_TRANSPORT_INFO_0 TransportInfo,
|
|||
|
OUT LPDWORD ErrorParameter OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is the NetWkstaTransportAdd entry point in the
|
|||
|
Workstation service.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - Supplies the name of server to execute this function
|
|||
|
|
|||
|
Level - Supplies the requested level of information.
|
|||
|
|
|||
|
TransportInfo - Supplies the information structure to add a new transport.
|
|||
|
|
|||
|
ErrorParameter - Returns the identifier to the invalid parameter if this
|
|||
|
function returns ERROR_INVALID_PARAMETER.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(ServerName);
|
|||
|
|
|||
|
//
|
|||
|
// Only admins can add a transport. Validate access.
|
|||
|
//
|
|||
|
if (NetpAccessCheckAndAudit(
|
|||
|
WORKSTATION_DISPLAY_NAME, // Subsystem name
|
|||
|
(LPTSTR) CONFIG_INFO_OBJECT, // Object type name
|
|||
|
ConfigurationInfoSd, // Security descriptor
|
|||
|
WKSTA_CONFIG_INFO_SET, // Desired access
|
|||
|
&WsConfigInfoMapping // Generic mapping
|
|||
|
) != NERR_Success) {
|
|||
|
|
|||
|
return ERROR_ACCESS_DENIED;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// 0 is the only valid level
|
|||
|
//
|
|||
|
if (Level != 0) {
|
|||
|
return ERROR_INVALID_LEVEL;
|
|||
|
}
|
|||
|
|
|||
|
if (TransportInfo->wkti0_transport_name == NULL) {
|
|||
|
RETURN_INVALID_PARAMETER(ErrorParameter, TRANSPORT_NAME_PARMNUM);
|
|||
|
}
|
|||
|
|
|||
|
return WsBindTransport(
|
|||
|
TransportInfo->wkti0_transport_name,
|
|||
|
TransportInfo->wkti0_quality_of_service,
|
|||
|
ErrorParameter
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
NetrWkstaTransportDel (
|
|||
|
IN LPTSTR ServerName OPTIONAL,
|
|||
|
IN LPTSTR TransportName,
|
|||
|
IN DWORD ForceLevel
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is the NetWkstaTransportDel entry point in the
|
|||
|
Workstation service.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - Supplies the name of server to execute this function
|
|||
|
|
|||
|
TransportName - Supplies the name of the transport to delete.
|
|||
|
|
|||
|
ForceLevel - Supplies the level of force to delete the tree connections on
|
|||
|
the transport we are unbinding from.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(ServerName);
|
|||
|
|
|||
|
//
|
|||
|
// Only admins can delete a transport. Validate access.
|
|||
|
//
|
|||
|
if (NetpAccessCheckAndAudit(
|
|||
|
WORKSTATION_DISPLAY_NAME, // Subsystem name
|
|||
|
(LPTSTR) CONFIG_INFO_OBJECT, // Object type name
|
|||
|
ConfigurationInfoSd, // Security descriptor
|
|||
|
WKSTA_CONFIG_INFO_SET, // Desired access
|
|||
|
&WsConfigInfoMapping // Generic mapping
|
|||
|
) != NERR_Success) {
|
|||
|
|
|||
|
return ERROR_ACCESS_DENIED;
|
|||
|
}
|
|||
|
|
|||
|
if (TransportName == NULL) {
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check that ForceLevel parameter is valid, which the redirector and
|
|||
|
// browser use to delete the connections on the transport we are
|
|||
|
// unbinding from.
|
|||
|
//
|
|||
|
switch (ForceLevel) {
|
|||
|
|
|||
|
case USE_FORCE:
|
|||
|
ForceLevel = USE_NOFORCE;
|
|||
|
break;
|
|||
|
|
|||
|
case USE_NOFORCE:
|
|||
|
case USE_LOTS_OF_FORCE:
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
return WsUnbindTransport(TransportName, ForceLevel);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsGetSystemInfo(
|
|||
|
IN DWORD Level,
|
|||
|
OUT LPBYTE *BufferPointer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function calls the Redirector FSD, the LSA subsystem and the
|
|||
|
MSV1_0 authentication package, and the Datagram Receiver DD to get
|
|||
|
the system wide information returned by NetWkstaGetInfo API.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Level - Supplies the requested level of information.
|
|||
|
|
|||
|
BufferPointer - Returns a pointer to a buffer which contains the
|
|||
|
requested workstation information.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
DWORD NumberOfLoggedOnUsers = 1;
|
|||
|
|
|||
|
//
|
|||
|
// Get number of logged on users from the MSV1_0 authentication package
|
|||
|
// if Level == 102.
|
|||
|
//
|
|||
|
if (Level == 102) {
|
|||
|
|
|||
|
PMSV1_0_ENUMUSERS_RESPONSE EnumUsersResponse = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Ask authentication package to enumerate users who are physically
|
|||
|
// logged to the local machine.
|
|||
|
//
|
|||
|
if ((status = WsLsaEnumUsers(
|
|||
|
(LPBYTE *) &EnumUsersResponse
|
|||
|
)) != NERR_Success) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
if (EnumUsersResponse == NULL) {
|
|||
|
return ERROR_GEN_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
NumberOfLoggedOnUsers = EnumUsersResponse->NumberOfLoggedOnUsers;
|
|||
|
|
|||
|
(VOID) LsaFreeReturnBuffer(EnumUsersResponse);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Put all the data collected into output buffer allocated by this routine.
|
|||
|
//
|
|||
|
return WsFillSystemBufferInfo(
|
|||
|
Level,
|
|||
|
NumberOfLoggedOnUsers,
|
|||
|
BufferPointer
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsGetPlatformInfo(
|
|||
|
IN DWORD Level,
|
|||
|
OUT LPBYTE *BufferPointer
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function calls the Redirector FSD to get the Redirector platform
|
|||
|
specific information returned by NetWkstaGetInfo API.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Level - Supplies the requested level of information.
|
|||
|
|
|||
|
BufferPointer - Returns the pointer a buffer which contains the requested
|
|||
|
redirector specific information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
LMR_REQUEST_PACKET Rrp; // Redirector request packet
|
|||
|
PWKSTA_INFO_502 Info;
|
|||
|
|
|||
|
//
|
|||
|
// There is only one redirector info level: 502.
|
|||
|
//
|
|||
|
NetpAssert(Level == 502);
|
|||
|
|
|||
|
//
|
|||
|
// Set up request packet. Output buffer structure is of configuration
|
|||
|
// information type.
|
|||
|
//
|
|||
|
Rrp.Version = REQUEST_PACKET_VERSION;
|
|||
|
Rrp.Level = Level;
|
|||
|
Rrp.Type = ConfigInformation;
|
|||
|
|
|||
|
//
|
|||
|
// Get the requested information from the Redirector. This routine
|
|||
|
// allocates the returned buffer.
|
|||
|
//
|
|||
|
status = WsDeviceControlGetInfo(
|
|||
|
Redirector,
|
|||
|
WsRedirDeviceHandle,
|
|||
|
FSCTL_LMR_GET_CONFIG_INFO,
|
|||
|
&Rrp,
|
|||
|
sizeof(LMR_REQUEST_PACKET),
|
|||
|
BufferPointer,
|
|||
|
sizeof(WKSTA_INFO_502),
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (status == NERR_Success) {
|
|||
|
Info = (PWKSTA_INFO_502) *BufferPointer;
|
|||
|
|
|||
|
//
|
|||
|
// Fill datagram receiver fields in level 502 structure from global
|
|||
|
// Workstation buffer (WSBUF). There are no FSCtl APIs to get or
|
|||
|
// set them in the datagram receiver.
|
|||
|
//
|
|||
|
Info->wki502_num_mailslot_buffers =
|
|||
|
WSBUF.wki502_num_mailslot_buffers;
|
|||
|
Info->wki502_num_srv_announce_buffers =
|
|||
|
WSBUF.wki502_num_srv_announce_buffers;
|
|||
|
Info->wki502_max_illegal_datagram_events =
|
|||
|
WSBUF.wki502_max_illegal_datagram_events;
|
|||
|
Info->wki502_illegal_datagram_event_reset_frequency =
|
|||
|
WSBUF.wki502_illegal_datagram_event_reset_frequency;
|
|||
|
Info->wki502_log_election_packets =
|
|||
|
WSBUF.wki502_log_election_packets;;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsValidateAndSetWksta(
|
|||
|
IN DWORD Level,
|
|||
|
IN LPBYTE Buffer,
|
|||
|
OUT LPDWORD ErrorParameter OPTIONAL,
|
|||
|
OUT LPDWORD Parmnum
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function sets the user specified config fields into the global
|
|||
|
WsInfo.WsConfigBuf (WSBUF) buffer and validates that the fields
|
|||
|
are valid.
|
|||
|
|
|||
|
It returns the associated parmnum value so that the caller can
|
|||
|
specify it to the redirector.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Level - Supplies the requested level of information.
|
|||
|
|
|||
|
Buffer - Supplies a buffer which contains the user specified config
|
|||
|
fields.
|
|||
|
|
|||
|
ErrorParameter - Receives the parmnum value of the field that is
|
|||
|
invalid if ERROR_INVALID_PARAMETER is returned.
|
|||
|
|
|||
|
Parmnum - Receives the parmnum for the field(s) being set.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
DWORD i;
|
|||
|
|
|||
|
//
|
|||
|
// Perform range checking
|
|||
|
//
|
|||
|
|
|||
|
switch (Level) {
|
|||
|
|
|||
|
case 502: // Set all fields
|
|||
|
WSBUF = *((PWKSTA_INFO_502) Buffer);
|
|||
|
*Parmnum = PARMNUM_ALL;
|
|||
|
break;
|
|||
|
|
|||
|
case 1010: // char_wait
|
|||
|
WSBUF.wki502_char_wait = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_CHARWAIT_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1011: // collection_time
|
|||
|
WSBUF.wki502_collection_time = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_CHARTIME_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1012: // maximum_collection_count
|
|||
|
WSBUF.wki502_maximum_collection_count = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_CHARCOUNT_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1013: // keep_conn
|
|||
|
WSBUF.wki502_keep_conn = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_KEEPCONN_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1018: // sess_timeout
|
|||
|
WSBUF.wki502_sess_timeout = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_SESSTIMEOUT_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1023: // siz_char_buf
|
|||
|
WSBUF.wki502_siz_char_buf = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_SIZCHARBUF_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1033: // max_threads
|
|||
|
WSBUF.wki502_max_threads = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_MAXTHREADS_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1041: // lock_quota
|
|||
|
WSBUF.wki502_lock_quota = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_LOCKQUOTA_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1042: // lock_increment
|
|||
|
WSBUF.wki502_lock_increment = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_LOCKINCREMENT_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1043: // lock_maximum
|
|||
|
WSBUF.wki502_lock_maximum = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_LOCKMAXIMUM_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1044: // pipe_increment
|
|||
|
WSBUF.wki502_pipe_increment = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_PIPEINCREMENT_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1045: // pipe_maximum
|
|||
|
WSBUF.wki502_pipe_maximum = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_PIPEMAXIMUM_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1046: // dormant_file_limit
|
|||
|
WSBUF.wki502_dormant_file_limit = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_DORMANTFILELIMIT_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1047: // cache_file_timeout
|
|||
|
WSBUF.wki502_cache_file_timeout = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_CACHEFILETIMEOUT_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1048: // use_opportunistic_locking
|
|||
|
WSBUF.wki502_use_opportunistic_locking = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_USEOPPORTUNISTICLOCKING_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1049: // use_unlock_behind
|
|||
|
WSBUF.wki502_use_unlock_behind = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_USEUNLOCKBEHIND_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1050: // use_close_behind
|
|||
|
WSBUF.wki502_use_close_behind = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_USECLOSEBEHIND_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1051: // buf_named_pipes
|
|||
|
WSBUF.wki502_buf_named_pipes = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_BUFFERNAMEDPIPES_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1052: // use_lock_read_unlock
|
|||
|
WSBUF.wki502_use_lock_read_unlock = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_USELOCKANDREADANDUNLOCK_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1053: // utilize_nt_caching
|
|||
|
WSBUF.wki502_utilize_nt_caching = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_UTILIZENTCACHING_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1054: // use_raw_read
|
|||
|
WSBUF.wki502_use_raw_read = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_USERAWREAD_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1055: // use_raw_write
|
|||
|
WSBUF.wki502_use_raw_write = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_USERAWWRITE_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1056: // use_write_raw_data
|
|||
|
WSBUF.wki502_use_write_raw_data = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_USEWRITERAWWITHDATA_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1057: // use_encryption
|
|||
|
WSBUF.wki502_use_encryption = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_USEENCRYPTION_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1058: // buf_files_deny_write
|
|||
|
WSBUF.wki502_buf_files_deny_write = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_BUFFILESWITHDENYWRITE_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1059: // buf_read_only_files
|
|||
|
WSBUF.wki502_buf_read_only_files = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_BUFFERREADONLYFILES_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1060: // force_core_create_mode
|
|||
|
WSBUF.wki502_force_core_create_mode = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_FORCECORECREATEMODE_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1061: // use_512_byte_max_transfer
|
|||
|
WSBUF.wki502_use_512_byte_max_transfer = *((LPBOOL) Buffer);
|
|||
|
*Parmnum = WKSTA_USE512BYTESMAXTRANSFER_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
case 1062: // read_ahead_throughput
|
|||
|
WSBUF.wki502_read_ahead_throughput = *((LPDWORD) Buffer);
|
|||
|
*Parmnum = WKSTA_READAHEADTHRUPUT_PARMNUM;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
if (ErrorParameter != NULL) {
|
|||
|
*ErrorParameter = PARM_ERROR_UNKNOWN;
|
|||
|
}
|
|||
|
return ERROR_INVALID_LEVEL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
for (i = 0; WsInfo.WsConfigFields[i].Keyword != NULL; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// Check the range of all fields. If any fail, we return
|
|||
|
// ERROR_INVALID_PARAMETER.
|
|||
|
//
|
|||
|
if (((WsInfo.WsConfigFields[i].DataType == DWordType) &&
|
|||
|
(*(WsInfo.WsConfigFields[i].FieldPtr) <
|
|||
|
WsInfo.WsConfigFields[i].Minimum ||
|
|||
|
*(WsInfo.WsConfigFields[i].FieldPtr) >
|
|||
|
WsInfo.WsConfigFields[i].Maximum))
|
|||
|
||
|
|||
|
((WsInfo.WsConfigFields[i].DataType == BooleanType) &&
|
|||
|
(*(WsInfo.WsConfigFields[i].FieldPtr) != TRUE &&
|
|||
|
*(WsInfo.WsConfigFields[i].FieldPtr) != FALSE))) {
|
|||
|
|
|||
|
//
|
|||
|
// We have a problem if this is not a field we want
|
|||
|
// to set, and we still happen to find a bad value.
|
|||
|
//
|
|||
|
NetpAssert((*Parmnum == PARMNUM_ALL) ||
|
|||
|
(*Parmnum == WsInfo.WsConfigFields[i].Parmnum));
|
|||
|
|
|||
|
IF_DEBUG(INFO) {
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA "Parameter %s has bad value %u, parmnum %u\n",
|
|||
|
WsInfo.WsConfigFields[i].Keyword,
|
|||
|
*(WsInfo.WsConfigFields[i].FieldPtr),
|
|||
|
WsInfo.WsConfigFields[i].Parmnum
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
RETURN_INVALID_PARAMETER(
|
|||
|
ErrorParameter,
|
|||
|
WsInfo.WsConfigFields[i].Parmnum
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsUpdateRedirToMatchWksta(
|
|||
|
IN DWORD Parmnum,
|
|||
|
OUT LPDWORD ErrorParameter OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function calls the redirector to set the redirector platform specific
|
|||
|
information with the values found in the global WsInfo.WsConfigBuf (WSBUF)
|
|||
|
buffer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Parmnum - Supplies the parameter number of the field if a single field
|
|||
|
is being set. If all fields are being set, this value is PARMNUM_ALL.
|
|||
|
|
|||
|
|
|||
|
ErrorParameter - Returns the identifier to the invalid parameter in Buffer
|
|||
|
if this function returns ERROR_INVALID_PARAMETER.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS ApiStatus;
|
|||
|
LMR_REQUEST_PACKET Rrp; // Redirector request packet
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set up request packet. Input buffer structure is of configuration
|
|||
|
// information type.
|
|||
|
//
|
|||
|
Rrp.Version = REQUEST_PACKET_VERSION;
|
|||
|
Rrp.Level = 502;
|
|||
|
Rrp.Type = ConfigInformation;
|
|||
|
Rrp.Parameters.Set.WkstaParameter = Parmnum;
|
|||
|
|
|||
|
//
|
|||
|
// Set the information in the Redirector.
|
|||
|
//
|
|||
|
ApiStatus = WsRedirFsControl(
|
|||
|
WsRedirDeviceHandle,
|
|||
|
FSCTL_LMR_SET_CONFIG_INFO,
|
|||
|
&Rrp,
|
|||
|
sizeof(LMR_REQUEST_PACKET),
|
|||
|
(PVOID) &WSBUF,
|
|||
|
sizeof(WSBUF),
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (ApiStatus == ERROR_INVALID_PARAMETER && ARGUMENT_PRESENT(ErrorParameter)) {
|
|||
|
|
|||
|
IF_DEBUG(INFO) {
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA "NetrWkstaSetInfo: invalid parameter is %lu\n",
|
|||
|
Rrp.Parameters.Set.WkstaParameter));
|
|||
|
}
|
|||
|
|
|||
|
*ErrorParameter = Rrp.Parameters.Set.WkstaParameter;
|
|||
|
}
|
|||
|
|
|||
|
return ApiStatus;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
WsUpdateRegistryToMatchWksta(
|
|||
|
IN DWORD Level,
|
|||
|
IN LPBYTE Buffer,
|
|||
|
OUT LPDWORD ErrorParameter OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function calls the registry to update the platform specific
|
|||
|
information in the registry.
|
|||
|
|
|||
|
If any write operation to the registry fails, there is nothing we can
|
|||
|
do about it because chances are good that we will not be able to back
|
|||
|
out the changes since that requires more writes to the registry. When
|
|||
|
this happens, the discrepancy between the registry and the redirector
|
|||
|
will be straightened out when next key change notify occurs.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Level - Supplies the level of information.
|
|||
|
|
|||
|
Buffer - Supplies a buffer which contains the information structure
|
|||
|
to set.
|
|||
|
|
|||
|
ErrorParameter - Returns the identifier to the invalid parameter in Buffer
|
|||
|
if this function returns ERROR_INVALID_PARAMETER.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS ApiStatus;
|
|||
|
LPNET_CONFIG_HANDLE SectionHandle = NULL;
|
|||
|
DWORD i;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Open section of config data.
|
|||
|
//
|
|||
|
ApiStatus = NetpOpenConfigData(
|
|||
|
&SectionHandle,
|
|||
|
NULL, // Local server.
|
|||
|
SECT_NT_WKSTA, // Section name.
|
|||
|
FALSE // Don't want read-only access.
|
|||
|
);
|
|||
|
|
|||
|
if (ApiStatus != NERR_Success) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Macro to update one value in the registry.
|
|||
|
// Assumes that Buffer starts with the new value for this field.
|
|||
|
//
|
|||
|
|
|||
|
#define WRITE_ONE_PARM_TO_REGISTRY( KeyNamePart, TypeFlag ) \
|
|||
|
{ \
|
|||
|
if (TypeFlag == BooleanType) { \
|
|||
|
(void) WsSetConfigBool( \
|
|||
|
SectionHandle, \
|
|||
|
WKSTA_KEYWORD_ ## KeyNamePart, \
|
|||
|
* ((LPBOOL) Buffer) ); \
|
|||
|
} else { \
|
|||
|
NetpAssert( TypeFlag == DWordType ); \
|
|||
|
(void) WsSetConfigDword( \
|
|||
|
SectionHandle, \
|
|||
|
WKSTA_KEYWORD_ ## KeyNamePart, \
|
|||
|
* ((LPDWORD) Buffer) ); \
|
|||
|
} \
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update field based on the info level.
|
|||
|
//
|
|||
|
|
|||
|
switch (Level) {
|
|||
|
|
|||
|
case 502: // Set all fields
|
|||
|
|
|||
|
for (i = 0; WsInfo.WsConfigFields[i].Keyword != NULL; i++) {
|
|||
|
//
|
|||
|
// Write this field to the registry.
|
|||
|
//
|
|||
|
if (WsInfo.WsConfigFields[i].DataType == DWordType) {
|
|||
|
|
|||
|
(void) WsSetConfigDword(
|
|||
|
SectionHandle,
|
|||
|
WsInfo.WsConfigFields[i].Keyword,
|
|||
|
* ((LPDWORD) WsInfo.WsConfigFields[i].FieldPtr)
|
|||
|
);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
NetpAssert(WsInfo.WsConfigFields[i].DataType == BooleanType);
|
|||
|
|
|||
|
(void) WsSetConfigBool(
|
|||
|
SectionHandle,
|
|||
|
WsInfo.WsConfigFields[i].Keyword,
|
|||
|
* ((LPBOOL) WsInfo.WsConfigFields[i].FieldPtr)
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case 1010: // char_wait
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( CHARWAIT, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1011: // collection_time
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( COLLECTIONTIME, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1012: // maximum_collection_count
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( MAXCOLLECTIONCOUNT, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1013: // keep_conn
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( KEEPCONN, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1018: // sess_timeout
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( SESSTIMEOUT, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1023: // siz_char_buf
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( SIZCHARBUF, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1033: // max_threads
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( MAXTHREADS, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1041: // lock_quota
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( LOCKQUOTA, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1042: // lock_increment
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( LOCKINCREMENT, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1043: // lock_maximum
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( LOCKMAXIMUM, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1044: // pipe_increment
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( PIPEINCREMENT, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1045: // pipe_maximum
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( PIPEMAXIMUM, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1046: // dormant_file_limit
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( DORMANTFILELIMIT, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1047: // cache_file_timeout
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( CACHEFILETIMEOUT, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1048: // use_opportunistic_locking
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( USEOPLOCKING, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1049: // use_unlock_behind
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( USEUNLOCKBEHIND, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1050: // use_close_behind
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( USECLOSEBEHIND, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1051: // buf_named_pipes
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( BUFNAMEDPIPES, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1052: // use_lock_read_unlock
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( USELOCKREADUNLOCK, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1053: // utilize_nt_caching
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( UTILIZENTCACHING, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1054: // use_raw_read
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( USERAWREAD, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1055: // use_raw_write
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( USERAWWRITE, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1056: // use_write_raw_data
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( USEWRITERAWDATA, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1057: // use_encryption
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( USEENCRYPTION, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1058: // buf_files_deny_write
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( BUFFILESDENYWRITE, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1059: // buf_read_only_files
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( BUFREADONLYFILES, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1060: // force_core_create_mode
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( FORCECORECREATE, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1061: // use_512_byte_max_transfer
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( USE512BYTEMAXTRANS, BooleanType );
|
|||
|
break;
|
|||
|
|
|||
|
case 1062: // read_ahead_throughput
|
|||
|
WRITE_ONE_PARM_TO_REGISTRY( READAHEADTHRUPUT, DWordType );
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
default:
|
|||
|
//
|
|||
|
// This should never happen
|
|||
|
//
|
|||
|
NetpAssert(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
if (SectionHandle != NULL) {
|
|||
|
(VOID) NetpCloseConfigData( SectionHandle );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsFillSystemBufferInfo(
|
|||
|
IN DWORD Level,
|
|||
|
IN DWORD NumberOfLoggedOnUsers,
|
|||
|
OUT LPBYTE *OutputBuffer
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function calculates the exact length of the output buffer needed,
|
|||
|
allocates that amount, and fill the output buffer with all the requested
|
|||
|
system-wide workstation information.
|
|||
|
|
|||
|
NOTE: This function assumes that info structure level 102 is a superset
|
|||
|
of info structure level 100 and 101, and that the offset to each
|
|||
|
common field is exactly the same. This allows us to take
|
|||
|
advantage of a switch statement without a break between the levels.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Level - Supplies the level of information to be returned.
|
|||
|
|
|||
|
NumberOfLoggedOnUsers - Supplies the number of users logged on
|
|||
|
interactively.
|
|||
|
|
|||
|
OutputBuffer - Returns a pointer to the buffer allocated by this routine
|
|||
|
which is filled with the requested system-wide workstation
|
|||
|
information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failing to allocate the
|
|||
|
output buffer.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PWKSTA_INFO_102 WkstaSystemInfo;
|
|||
|
|
|||
|
LPBYTE FixedDataEnd;
|
|||
|
LPTSTR EndOfVariableData;
|
|||
|
|
|||
|
DWORD SystemInfoFixedLength = SYSTEM_INFO_FIXED_LENGTH(Level);
|
|||
|
DWORD TotalBytesNeeded = SystemInfoFixedLength +
|
|||
|
(WsInfo.WsComputerNameLength +
|
|||
|
WsInfo.WsPrimaryDomainNameLength +
|
|||
|
3) * sizeof(TCHAR); // include NULL character
|
|||
|
// for LAN root
|
|||
|
|
|||
|
|
|||
|
if ((*OutputBuffer = MIDL_user_allocate(TotalBytesNeeded)) == NULL) {
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
RtlZeroMemory((PVOID) *OutputBuffer, TotalBytesNeeded);
|
|||
|
|
|||
|
WkstaSystemInfo = (PWKSTA_INFO_102) *OutputBuffer;
|
|||
|
|
|||
|
FixedDataEnd = (LPBYTE) ((DWORD_PTR) *OutputBuffer + SystemInfoFixedLength);
|
|||
|
EndOfVariableData = (LPTSTR) ((DWORD_PTR) *OutputBuffer + TotalBytesNeeded);
|
|||
|
|
|||
|
//
|
|||
|
// Put the data into the output buffer.
|
|||
|
//
|
|||
|
switch (Level) {
|
|||
|
|
|||
|
case 102:
|
|||
|
|
|||
|
WkstaSystemInfo->wki102_logged_on_users = NumberOfLoggedOnUsers;
|
|||
|
|
|||
|
case 101:
|
|||
|
|
|||
|
//
|
|||
|
// LAN root is set to NULL on NT.
|
|||
|
//
|
|||
|
NetpCopyStringToBuffer(
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
FixedDataEnd,
|
|||
|
&EndOfVariableData,
|
|||
|
&WkstaSystemInfo->wki102_lanroot
|
|||
|
);
|
|||
|
|
|||
|
case 100:
|
|||
|
|
|||
|
WkstaSystemInfo->wki102_platform_id = WsInfo.RedirectorPlatform;
|
|||
|
WkstaSystemInfo->wki102_ver_major = WsInfo.MajorVersion;
|
|||
|
WkstaSystemInfo->wki102_ver_minor = WsInfo.MinorVersion;
|
|||
|
|
|||
|
NetpCopyStringToBuffer(
|
|||
|
WsInfo.WsComputerName,
|
|||
|
WsInfo.WsComputerNameLength,
|
|||
|
FixedDataEnd,
|
|||
|
&EndOfVariableData,
|
|||
|
&WkstaSystemInfo->wki102_computername
|
|||
|
);
|
|||
|
|
|||
|
NetpCopyStringToBuffer(
|
|||
|
WsInfo.WsPrimaryDomainName,
|
|||
|
WsInfo.WsPrimaryDomainNameLength,
|
|||
|
FixedDataEnd,
|
|||
|
&EndOfVariableData,
|
|||
|
&WkstaSystemInfo->wki102_langroup
|
|||
|
);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
//
|
|||
|
// This should never happen.
|
|||
|
//
|
|||
|
NetpKdPrint(("WsFillSystemBufferInfo: Invalid level %lu\n", Level));
|
|||
|
NetpAssert(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
}
|