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.
7723 lines
228 KiB
7723 lines
228 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
enum.c
|
|
|
|
Abstract:
|
|
|
|
This module contains server, volume, and directory enumeration
|
|
routines supported by NetWare Workstation service.
|
|
|
|
Author:
|
|
|
|
Rita Wong (ritaw) 15-Feb-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <stdlib.h>
|
|
#include <nw.h>
|
|
#include <splutil.h>
|
|
#include <nwmisc.h>
|
|
#include <nwreg.h>
|
|
#include <nds.h>
|
|
#include <nwapi32.h>
|
|
|
|
|
|
VOID
|
|
GetLuid(
|
|
IN OUT PLUID plogonid
|
|
);
|
|
|
|
//-------------------------------------------------------------------//
|
|
// //
|
|
// Definitions //
|
|
// //
|
|
//-------------------------------------------------------------------//
|
|
|
|
//
|
|
// Other definitions
|
|
//
|
|
#define ONE_KB 1024
|
|
#define TWO_KB 2048
|
|
#define FOUR_KB 4096
|
|
#define EIGHT_KB 8192
|
|
|
|
#define TREECHAR L'*'
|
|
|
|
#define NW_VOLUME_NAME_LEN 256
|
|
#define NW_MAX_VOLUME_NUMBER 64
|
|
|
|
//
|
|
// This structure is orginally defined in nwapi32.c, it is redefined
|
|
// here so that the routine NWGetFileServerVersionInfo() can be called
|
|
// with it.
|
|
//
|
|
typedef struct _NWC_SERVER_INFO {
|
|
HANDLE hConn ;
|
|
UNICODE_STRING ServerString ;
|
|
} NWC_SERVER_INFO ;
|
|
|
|
//-------------------------------------------------------------------//
|
|
// //
|
|
// Local Function Prototypes //
|
|
// //
|
|
//-------------------------------------------------------------------//
|
|
|
|
DWORD
|
|
NwrOpenEnumServersCommon(
|
|
IN NW_ENUM_TYPE EnumType,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
);
|
|
|
|
DWORD
|
|
NwrOpenEnumCommon(
|
|
IN LPWSTR ContainerName,
|
|
IN NW_ENUM_TYPE EnumType,
|
|
IN DWORD_PTR StartingPoint,
|
|
IN BOOL ValidateUserFlag,
|
|
IN LPWSTR UserName OPTIONAL,
|
|
IN LPWSTR Password OPTIONAL,
|
|
IN ULONG CreateDisposition,
|
|
IN ULONG CreateOptions,
|
|
OUT LPDWORD ClassTypeOfNDSLeaf,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
);
|
|
|
|
DWORD
|
|
NwEnumContextInfo(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwEnumServersAndNdsTrees(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwEnumPrintServers(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwEnumVolumes(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwEnumNdsSubTrees_Disk(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwEnumNdsSubTrees_Print(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwEnumNdsSubTrees_Any(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwEnumQueues(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwEnumVolumesQueues(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwEnumDirectories(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwEnumPrintQueues(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
);
|
|
|
|
DWORD
|
|
NwGetFirstDirectoryEntry(
|
|
IN HANDLE DirHandle,
|
|
OUT LPWSTR *DirEntry
|
|
);
|
|
|
|
DWORD
|
|
NwGetNextDirectoryEntry(
|
|
IN HANDLE DirHandle,
|
|
OUT LPWSTR *DirEntry
|
|
);
|
|
|
|
DWORD
|
|
NwGetFirstNdsSubTreeEntry(
|
|
OUT LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD BufferSize
|
|
);
|
|
|
|
DWORD
|
|
NwGetNextNdsSubTreeEntry(
|
|
OUT LPNW_ENUM_CONTEXT ContextHandle
|
|
);
|
|
|
|
BYTE
|
|
NwGetSubTreeData(
|
|
IN DWORD_PTR NdsRawDataPtr,
|
|
OUT LPWSTR * SubTreeName,
|
|
OUT LPDWORD ResourceScope,
|
|
OUT LPDWORD ResourceType,
|
|
OUT LPDWORD ResourceDisplayType,
|
|
OUT LPDWORD ResourceUsage,
|
|
OUT LPWSTR * StrippedObjectName
|
|
);
|
|
|
|
VOID
|
|
NwStripNdsUncName(
|
|
IN LPWSTR ObjectName,
|
|
OUT LPWSTR * StrippedObjectName
|
|
);
|
|
|
|
#define VERIFY_ERROR_NOT_A_NDS_TREE 0x1010FFF0
|
|
#define VERIFY_ERROR_PATH_NOT_FOUND 0x1010FFF1
|
|
|
|
DWORD
|
|
NwVerifyNDSObject(
|
|
IN LPWSTR lpNDSObjectNamePath,
|
|
OUT LPWSTR * lpFullNDSObjectNamePath,
|
|
OUT LPDWORD lpClassType,
|
|
OUT LPDWORD lpResourceScope,
|
|
OUT LPDWORD lpResourceType,
|
|
OUT LPDWORD lpResourceDisplayType,
|
|
OUT LPDWORD lpResourceUsage
|
|
);
|
|
|
|
DWORD
|
|
NwVerifyBinderyObject(
|
|
IN LPWSTR lpBinderyObjectNamePath,
|
|
OUT LPWSTR * lpFullBinderyObjectNamePath,
|
|
OUT LPDWORD lpClassType,
|
|
OUT LPDWORD lpResourceScope,
|
|
OUT LPDWORD lpResourceType,
|
|
OUT LPDWORD lpResourceDisplayType,
|
|
OUT LPDWORD lpResourceUsage
|
|
);
|
|
|
|
DWORD
|
|
NwGetNDSPathInfo(
|
|
IN LPWSTR lpNDSObjectNamePath,
|
|
OUT LPWSTR * lpSystemObjectNamePath,
|
|
OUT LPWSTR * lpSystemPathPart,
|
|
OUT LPDWORD lpClassType,
|
|
OUT LPDWORD lpResourceScope,
|
|
OUT LPDWORD lpResourceType,
|
|
OUT LPDWORD lpResourceDisplayType,
|
|
OUT LPDWORD lpResourceUsage
|
|
);
|
|
|
|
DWORD
|
|
NwGetBinderyPathInfo(
|
|
IN LPWSTR lpBinderyObjectNamePath,
|
|
OUT LPWSTR * lpSystemObjectNamePath,
|
|
OUT LPWSTR * lpSystemPathPart,
|
|
OUT LPDWORD lpClassType,
|
|
OUT LPDWORD lpResourceScope,
|
|
OUT LPDWORD lpResourceType,
|
|
OUT LPDWORD lpResourceDisplayType,
|
|
OUT LPDWORD lpResourceUsage
|
|
);
|
|
|
|
BOOL
|
|
NwGetRemoteNameParent(
|
|
IN LPWSTR lpRemoteName,
|
|
OUT LPWSTR * lpRemoteNameParent
|
|
);
|
|
|
|
int __cdecl
|
|
SortFunc(
|
|
IN CONST VOID *p1,
|
|
IN CONST VOID *p2
|
|
);
|
|
|
|
DWORD
|
|
NwGetConnectionInformation(
|
|
IN LPWSTR lpName,
|
|
OUT LPWSTR lpUserName,
|
|
OUT LPWSTR lpHostServer
|
|
);
|
|
|
|
|
|
VOID
|
|
NwpGetUncInfo(
|
|
IN LPWSTR lpstrUnc,
|
|
OUT WORD * slashCount,
|
|
OUT BOOL * isNdsUnc,
|
|
OUT LPWSTR * FourthSlash
|
|
);
|
|
|
|
DWORD
|
|
NwpGetCurrentUserRegKey(
|
|
IN DWORD DesiredAccess,
|
|
OUT HKEY *phKeyCurrentUser
|
|
);
|
|
|
|
DWORD
|
|
NwQueryInfo(
|
|
OUT LPWSTR *ppszPreferredSrv
|
|
);
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumContextInfo(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN DWORD ConnectionType,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a new context handle and initializes it
|
|
for enumerating context information (i.e. NDS user context objects
|
|
and/or NetWare bindery server connections).
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
|
|
not be allocated.
|
|
|
|
NO_ERROR - Call was successful.
|
|
|
|
--*/
|
|
{
|
|
LPWSTR pszCurrentContext = NULL;
|
|
DWORD dwPrintOptions;
|
|
DWORD status = NwQueryInfo( &pszCurrentContext );
|
|
WCHAR Context[MAX_NDS_NAME_CHARS];
|
|
LPNW_ENUM_CONTEXT ContextHandle;
|
|
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
UNREFERENCED_PARAMETER(ConnectionType);
|
|
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("\nNWWORKSTATION: NwrOpenEnumContextInfo\n"));
|
|
}
|
|
#endif
|
|
|
|
if ( pszCurrentContext &&
|
|
status == NO_ERROR )
|
|
{
|
|
if ( pszCurrentContext[0] == TREECHAR )
|
|
{
|
|
wcscpy( Context, L"\\\\" );
|
|
wcscat( Context, pszCurrentContext + 1 );
|
|
|
|
LocalFree( pszCurrentContext );
|
|
pszCurrentContext = NULL;
|
|
|
|
return NwrOpenEnumCommon(
|
|
Context,
|
|
NwsHandleListContextInfo_Tree,
|
|
(DWORD_PTR) -1,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL,
|
|
EnumHandle
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The user does not have a preferred NDS tree and context. They
|
|
// may have only a preferred server.
|
|
//
|
|
if ( pszCurrentContext[0] != 0 )
|
|
{
|
|
//
|
|
// There is a prefered server.
|
|
//
|
|
LocalFree( pszCurrentContext );
|
|
pszCurrentContext = NULL;
|
|
|
|
ContextHandle = (PVOID) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
sizeof(NW_ENUM_CONTEXT)
|
|
);
|
|
|
|
if (ContextHandle == NULL)
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwrOpenEnumContextInfo LocalAlloc Failed %lu\n", GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Initialize contents of the context handle structure.
|
|
//
|
|
ContextHandle->Signature = NW_HANDLE_SIGNATURE;
|
|
ContextHandle->HandleType = NwsHandleListContextInfo_Server;
|
|
ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
|
|
ContextHandle->ResumeId = (DWORD_PTR) -1;
|
|
|
|
// The following are set to zero due to the LMEM_ZEROINIT.
|
|
// ContextHandle->NdsRawDataBuffer = 0;
|
|
// ContextHandle->NdsRawDataSize = 0;
|
|
// ContextHandle->NdsRawDataId = 0;
|
|
// ContextHandle->NdsRawDataCount = 0;
|
|
// ContextHandle->TreeConnectionHandle = 0;
|
|
// ContextHandle->ConnectionType = 0;
|
|
|
|
//
|
|
// Return the newly created context.
|
|
//
|
|
*EnumHandle = (LPNWWKSTA_CONTEXT_HANDLE) ContextHandle;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// There is no information in the registry about the current user.
|
|
// We go ahead and make an enumeration handle and return success.
|
|
// Later, during a call to NPEnumResource, we will return zero items.
|
|
// This is done because there is no valid return code to tell the
|
|
// callee that we have no context information to provide.
|
|
//
|
|
ContextHandle = (PVOID) LocalAlloc( LMEM_ZEROINIT,
|
|
sizeof(NW_ENUM_CONTEXT) );
|
|
|
|
if (ContextHandle == NULL)
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwrOpenEnumContextInfo LocalAlloc Failed %lu\n", GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Initialize contents of the context handle structure.
|
|
//
|
|
ContextHandle->Signature = NW_HANDLE_SIGNATURE;
|
|
ContextHandle->HandleType = NwsHandleListContextInfo_Server;
|
|
ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
|
|
ContextHandle->ResumeId = 0; // This will tell NwrEnum to
|
|
// give up (i.e. we are done).
|
|
|
|
// The following are set to zero due to the LMEM_ZEROINIT.
|
|
// ContextHandle->NdsRawDataBuffer = 0;
|
|
// ContextHandle->NdsRawDataSize = 0;
|
|
// ContextHandle->NdsRawDataId = 0;
|
|
// ContextHandle->NdsRawDataCount = 0;
|
|
// ContextHandle->TreeConnectionHandle = 0;
|
|
// ContextHandle->ConnectionType = 0;
|
|
|
|
//
|
|
// Return the newly created context.
|
|
//
|
|
*EnumHandle = (LPNWWKSTA_CONTEXT_HANDLE) ContextHandle;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumServersAndNdsTrees(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a new context handle and initializes it
|
|
for enumerating the servers and NDS trees on the network.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
|
|
not be allocated.
|
|
|
|
NO_ERROR - Call was successful.
|
|
|
|
--*/ // NwrOpenEnumServersAndNdsTrees
|
|
{
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint( ("\nNWWORKSTATION: NwrOpenEnumServersAndNdsTrees\n") );
|
|
}
|
|
#endif
|
|
|
|
return NwrOpenEnumServersCommon(
|
|
NwsHandleListServersAndNdsTrees,
|
|
EnumHandle
|
|
);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NwOpenEnumPrintServers(
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a new context handle and initializes it
|
|
for enumerating the print servers on the network.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
|
|
not be allocated.
|
|
|
|
NO_ERROR - Call was successful.
|
|
|
|
--*/ // NwOpenEnumPrintServers
|
|
{
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint( ("\nNWWORKSTATION: NwOpenEnumPrintServers\n") );
|
|
}
|
|
#endif
|
|
|
|
return NwrOpenEnumServersCommon(
|
|
NwsHandleListPrintServers,
|
|
EnumHandle
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumVolumes(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN LPWSTR ServerName,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls a common routine which creates a new context
|
|
handle and initializes it for enumerating the volumes on a server.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
ServerName - Supplies the name of the server to enumerate volumes.
|
|
This name is prefixed by \\.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or reason for failure.
|
|
|
|
--*/ // NwrOpenEnumVolumes
|
|
{
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("\nNWWORKSTATION: NwrOpenEnumVolumes %ws\n",
|
|
ServerName));
|
|
}
|
|
#endif
|
|
|
|
return NwrOpenEnumCommon(
|
|
ServerName,
|
|
NwsHandleListVolumes,
|
|
0,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
EnumHandle
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumNdsSubTrees_Disk(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN LPWSTR ParentPathName,
|
|
OUT LPDWORD ClassTypeOfNDSLeaf,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls a common routine which creates a new context
|
|
handle and initializes it for enumerating the DISK object types
|
|
and containers of a sub-tree in a NDS tree.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
ParentPathName - Supplies the name of the tree and the path to a container
|
|
to enumerate sub-trees.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or reason for failure.
|
|
|
|
--*/ // NwrOpenEnumNdsSubTrees_Disk
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("\nNWWORKSTATION: NwrOpenEnumNdsSubTrees_Disk %ws\n",
|
|
ParentPathName));
|
|
}
|
|
#endif
|
|
|
|
return NwrOpenEnumCommon(
|
|
ParentPathName,
|
|
NwsHandleListNdsSubTrees_Disk,
|
|
0,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
0,
|
|
ClassTypeOfNDSLeaf,
|
|
EnumHandle
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumNdsSubTrees_Print(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN LPWSTR ParentPathName,
|
|
OUT LPDWORD ClassTypeOfNDSLeaf,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls a common routine which creates a new context
|
|
handle and initializes it for enumerating the PRINT object types
|
|
and containers of a sub-tree in a NDS tree.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
ParentPathName - Supplies the name of the tree and the path to a container
|
|
to enumerate sub-trees.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or reason for failure.
|
|
|
|
--*/ // NwrOpenEnumNdsSubTrees_Print
|
|
{
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("\nNWWORKSTATION: NwrOpenEnumNdsSubTrees_Print %ws\n",
|
|
ParentPathName));
|
|
}
|
|
#endif
|
|
|
|
return NwrOpenEnumCommon(
|
|
ParentPathName,
|
|
NwsHandleListNdsSubTrees_Print,
|
|
0,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
0,
|
|
ClassTypeOfNDSLeaf,
|
|
EnumHandle
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumNdsSubTrees_Any(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN LPWSTR ParentPathName,
|
|
OUT LPDWORD ClassTypeOfNDSLeaf,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls a common routine which creates a new context
|
|
handle and initializes it for enumerating the ANY object types
|
|
and containers of a sub-tree in a NDS tree.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
ParentPathName - Supplies the name of the tree and the path to a container
|
|
to enumerate sub-trees.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or reason for failure.
|
|
|
|
--*/ // NwrOpenEnumNdsSubTrees_Any
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("\nNWWORKSTATION: NwrOpenEnumNdsSubTrees_Any %ws\n",
|
|
ParentPathName));
|
|
}
|
|
#endif
|
|
|
|
return NwrOpenEnumCommon(
|
|
ParentPathName,
|
|
NwsHandleListNdsSubTrees_Any,
|
|
0,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
0,
|
|
ClassTypeOfNDSLeaf,
|
|
EnumHandle
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumQueues(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN LPWSTR ServerName,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls a common routine which creates a new context
|
|
handle and initializes it for enumerating the volumes on a server.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
ServerName - Supplies the name of the server to enumerate volumes.
|
|
This name is prefixed by \\.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or reason for failure.
|
|
|
|
--*/ // NwrOpenEnumQueues
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("\nNWWORKSTATION: NwrOpenEnumQueues %ws\n",
|
|
ServerName));
|
|
}
|
|
#endif
|
|
|
|
return NwrOpenEnumCommon(
|
|
ServerName,
|
|
NwsHandleListQueues,
|
|
(DWORD_PTR) -1,
|
|
TRUE,
|
|
NULL,
|
|
NULL,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
EnumHandle
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumVolumesQueues(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN LPWSTR ServerName,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls a common routine which creates a new context
|
|
handle and initializes it for enumerating the volumes/queues on a server.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
ServerName - Supplies the name of the server to enumerate volumes.
|
|
This name is prefixed by \\.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or reason for failure.
|
|
|
|
--*/ // NwrOpenEnumVolumesQueues
|
|
{
|
|
|
|
DWORD status;
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("\nNWWORKSTATION: NwrOpenEnumVolumesQueues %ws\n",
|
|
ServerName));
|
|
}
|
|
#endif
|
|
|
|
status = NwrOpenEnumCommon(
|
|
ServerName,
|
|
NwsHandleListVolumesQueues,
|
|
0,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
EnumHandle
|
|
);
|
|
|
|
if ( status == NO_ERROR )
|
|
((LPNW_ENUM_CONTEXT) *EnumHandle)->ConnectionType = CONNTYPE_DISK;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumDirectories(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN LPWSTR ParentPathName,
|
|
IN LPWSTR UserName OPTIONAL,
|
|
IN LPWSTR Password OPTIONAL,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls a common routine which creates a new context
|
|
handle and initializes it for enumerating the volumes on a server.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
ParentPathName - Supplies the parent path name in the format of
|
|
\\Server\Volume.
|
|
|
|
UserName - Supplies the username to connect with.
|
|
|
|
Password - Supplies the password to connect with.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or reason for failure.
|
|
|
|
--*/ //NwrOpenEnumDirectories
|
|
{
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("\nNWWORKSTATION: NwrOpenEnumDirectories %ws\n",
|
|
ParentPathName));
|
|
}
|
|
#endif
|
|
|
|
return NwrOpenEnumCommon(
|
|
ParentPathName,
|
|
NwsHandleListDirectories,
|
|
0,
|
|
FALSE,
|
|
UserName,
|
|
Password,
|
|
FILE_CREATE,
|
|
FILE_CREATE_TREE_CONNECTION |
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
EnumHandle
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwOpenEnumPrintQueues(
|
|
IN LPWSTR ServerName,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls a common routine which creates a new context
|
|
handle and initializes it for enumerating the print queues on a server.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
ServerName - Supplies the name of the server to enumerate volumes.
|
|
This name is prefixed by \\.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or reason for failure.
|
|
|
|
--*/ // NwOpenEnumPrintQueues
|
|
{
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("\nNWWORKSTATION: NwOpenEnumPrintQueues %ws\n",
|
|
ServerName));
|
|
}
|
|
#endif
|
|
|
|
return NwrOpenEnumCommon(
|
|
ServerName,
|
|
NwsHandleListPrintQueues,
|
|
(DWORD_PTR) -1,
|
|
TRUE,
|
|
NULL,
|
|
NULL,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
EnumHandle
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumServersCommon(
|
|
IN NW_ENUM_TYPE EnumType,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a new context handle and initializes it
|
|
for enumerating the servers on the network.
|
|
|
|
Arguments:
|
|
|
|
EnumType - Supplies the type of the object we want to enumerate
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
|
|
not be allocated.
|
|
|
|
NO_ERROR - Call was successful.
|
|
|
|
--*/ // NwrOpenEnumServersCommon
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
LPNW_ENUM_CONTEXT ContextHandle = NULL;
|
|
|
|
//
|
|
// Allocate memory for the context handle structure.
|
|
//
|
|
ContextHandle = (PVOID) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
sizeof(NW_ENUM_CONTEXT)
|
|
);
|
|
|
|
if (ContextHandle == NULL) {
|
|
KdPrint((
|
|
"NWWORKSTATION: NwrOpenEnumServersCommon LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Initialize contents of the context handle structure.
|
|
//
|
|
ContextHandle->Signature = NW_HANDLE_SIGNATURE;
|
|
ContextHandle->HandleType = EnumType;
|
|
ContextHandle->ResumeId = (DWORD_PTR) -1;
|
|
ContextHandle->NdsRawDataBuffer = 0x00000000;
|
|
ContextHandle->NdsRawDataSize = 0x00000000;
|
|
ContextHandle->NdsRawDataId = 0x00000000;
|
|
ContextHandle->NdsRawDataCount = 0x00000000;
|
|
|
|
//
|
|
// Set flag to indicate that we are going to enumerate NDS trees first.
|
|
//
|
|
ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NDS;
|
|
|
|
//
|
|
// Impersonate the client
|
|
//
|
|
if ((status = NwImpersonateClient()) != NO_ERROR)
|
|
{
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// We enum servers and nds trees from the preferred server.
|
|
//
|
|
status = NwOpenPreferredServer(
|
|
&ContextHandle->TreeConnectionHandle
|
|
);
|
|
|
|
(void) NwRevertToSelf() ;
|
|
|
|
if (status == NO_ERROR)
|
|
{
|
|
//
|
|
// Return the newly created context.
|
|
//
|
|
*EnumHandle = (LPNWWKSTA_CONTEXT_HANDLE) ContextHandle;
|
|
|
|
return status;
|
|
}
|
|
|
|
CleanExit:
|
|
if ( ContextHandle )
|
|
{
|
|
ContextHandle->Signature = 0x0BADBAD0;
|
|
|
|
(void) LocalFree((HLOCAL) ContextHandle);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrOpenEnumCommon(
|
|
IN LPWSTR ContainerName,
|
|
IN NW_ENUM_TYPE EnumType,
|
|
IN DWORD_PTR StartingPoint,
|
|
IN BOOL ValidateUserFlag,
|
|
IN LPWSTR UserName OPTIONAL,
|
|
IN LPWSTR Password OPTIONAL,
|
|
IN ULONG CreateDisposition,
|
|
IN ULONG CreateOptions,
|
|
OUT LPDWORD ClassTypeOfNDSLeaf,
|
|
OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is common code for creating a new context handle
|
|
and initializing it for enumerating either volumes, directories,
|
|
or NDS subtrees.
|
|
|
|
Arguments:
|
|
|
|
ContainerName - Supplies the full path name to the container object
|
|
we are enumerating from.
|
|
|
|
EnumType - Supplies the type of the object we want to enumerate
|
|
|
|
StartingPoint - Supplies the initial resume ID.
|
|
|
|
UserName - Supplies the username to connect with.
|
|
|
|
Password - Supplies the password to connect with.
|
|
|
|
EnumHandle - Receives the newly created context handle.
|
|
|
|
Return Value:
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
|
|
not be allocated.
|
|
|
|
NO_ERROR - Call was successful.
|
|
|
|
Other errors from failure to open a handle to the server.
|
|
|
|
--*/ // NwrOpenEnumCommon
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
NTSTATUS ntstatus = STATUS_SUCCESS;
|
|
LPNW_ENUM_CONTEXT ContextHandle = NULL;
|
|
LPWSTR StrippedContainerName = NULL;
|
|
BOOL fImpersonate = FALSE ;
|
|
|
|
if ( ClassTypeOfNDSLeaf )
|
|
*ClassTypeOfNDSLeaf = 0;
|
|
|
|
//
|
|
// Before we do anything, we need to convert the UNC passed to
|
|
// us. We need to get rid of any CN=XXX.OU=YYY.O=ZZZ references, and
|
|
// convert them to XXX.YYY.ZZZ format. Any NETRESOURCE that we generate
|
|
// will look like \\TREE\XXX.YYY.ZZZ for a NDS Unc. We do this to
|
|
// work around to a bug in WOW.EXE, that prevents 16 bit apps from
|
|
// being launched when the user types NDS paths with the CN= stuff in it.
|
|
//
|
|
NwStripNdsUncName( ContainerName, &StrippedContainerName );
|
|
|
|
if ( StrippedContainerName == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwrOpenEnumCommon LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the context handle structure and space for
|
|
// the ContainerName plus \. Now need one more for NULL terminator
|
|
// because it's already included in the structure.
|
|
//
|
|
ContextHandle = (PVOID) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
sizeof(NW_ENUM_CONTEXT) +
|
|
(wcslen(StrippedContainerName) + 1) * sizeof(WCHAR)
|
|
);
|
|
|
|
if (ContextHandle == NULL)
|
|
{
|
|
if ( StrippedContainerName )
|
|
{
|
|
(void) LocalFree((HLOCAL) StrippedContainerName);
|
|
StrippedContainerName = NULL;
|
|
}
|
|
|
|
KdPrint(("NWWORKSTATION: NwrOpenEnumCommon LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Initialize contents of the context handle structure.
|
|
//
|
|
ContextHandle->Signature = NW_HANDLE_SIGNATURE;
|
|
ContextHandle->HandleType = EnumType;
|
|
ContextHandle->ResumeId = StartingPoint;
|
|
|
|
//
|
|
// These are set to zero due to LMEM_ZEROINIT.
|
|
//
|
|
// ContextHandle->NdsRawDataBuffer = 0;
|
|
// ContextHandle->NdsRawDataSize = 0;
|
|
// ContextHandle->NdsRawDataId = 0;
|
|
// ContextHandle->NdsRawDataCount = 0;
|
|
// ContextHandle->TreeConnectionHandle = 0;
|
|
|
|
//
|
|
// Impersonate the client
|
|
//
|
|
if ( ( status = NwImpersonateClient() ) != NO_ERROR )
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
fImpersonate = TRUE;
|
|
|
|
if ( EnumType == NwsHandleListNdsSubTrees_Disk ||
|
|
EnumType == NwsHandleListNdsSubTrees_Print ||
|
|
EnumType == NwsHandleListNdsSubTrees_Any ||
|
|
EnumType == NwsHandleListContextInfo_Tree )
|
|
{
|
|
WCHAR lpServerName[NW_MAX_SERVER_LEN];
|
|
UNICODE_STRING ServerName;
|
|
UNICODE_STRING ObjectName;
|
|
|
|
ServerName.Length = 0;
|
|
ServerName.MaximumLength = sizeof( lpServerName );
|
|
ServerName.Buffer = lpServerName;
|
|
|
|
ObjectName.Buffer = NULL;
|
|
|
|
if ( EnumType == NwsHandleListContextInfo_Tree )
|
|
{
|
|
ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
|
|
}
|
|
else
|
|
{
|
|
ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NDS;
|
|
}
|
|
|
|
ObjectName.MaximumLength = ( wcslen( StrippedContainerName ) + 1 ) *
|
|
sizeof( WCHAR );
|
|
|
|
ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer,
|
|
StrippedContainerName,
|
|
PARSE_NDS_GET_TREE_NAME );
|
|
|
|
if ( ObjectName.Length == 0 || ObjectName.Buffer == NULL )
|
|
{
|
|
status = ERROR_PATH_NOT_FOUND;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Open a NDS tree connection handle to \\treename
|
|
//
|
|
ntstatus = NwNdsOpenTreeHandle( &ObjectName,
|
|
&ContextHandle->TreeConnectionHandle );
|
|
|
|
if ( ntstatus != STATUS_SUCCESS )
|
|
{
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the path to the container to open.
|
|
//
|
|
ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer,
|
|
StrippedContainerName,
|
|
PARSE_NDS_GET_PATH_NAME
|
|
);
|
|
|
|
if ( ObjectName.Length == 0 )
|
|
{
|
|
UNICODE_STRING Root;
|
|
|
|
RtlInitUnicodeString(&Root, L"[Root]");
|
|
|
|
//
|
|
// Resolve the path to get a NDS object id of [Root].
|
|
//
|
|
ntstatus = NwNdsResolveName( ContextHandle->TreeConnectionHandle,
|
|
&Root,
|
|
&ContextHandle->dwOid,
|
|
&ServerName,
|
|
NULL,
|
|
0 );
|
|
|
|
if ( ntstatus != STATUS_SUCCESS )
|
|
{
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wcscpy(ContextHandle->ContainerName, StrippedContainerName);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Resolve the path to get a NDS object id.
|
|
//
|
|
ntstatus = NwNdsResolveName( ContextHandle->TreeConnectionHandle,
|
|
&ObjectName,
|
|
&ContextHandle->dwOid,
|
|
&ServerName,
|
|
NULL,
|
|
0 );
|
|
|
|
if ( ntstatus != STATUS_SUCCESS )
|
|
{
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wcscpy(ContextHandle->ContainerName, StrippedContainerName);
|
|
}
|
|
|
|
if ( ServerName.Length )
|
|
{
|
|
DWORD dwHandleType;
|
|
|
|
//
|
|
// NwNdsResolveName succeeded, but we were referred to
|
|
// another server, though ContextHandle->dwOid is still valid.
|
|
|
|
if ( ContextHandle->TreeConnectionHandle )
|
|
CloseHandle( ContextHandle->TreeConnectionHandle );
|
|
|
|
ContextHandle->TreeConnectionHandle = 0;
|
|
|
|
//
|
|
// Open a NDS generic connection handle to \\ServerName
|
|
//
|
|
ntstatus = NwNdsOpenGenericHandle( &ServerName,
|
|
&dwHandleType,
|
|
&ContextHandle->TreeConnectionHandle );
|
|
|
|
if ( ntstatus != STATUS_SUCCESS )
|
|
{
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
ASSERT( dwHandleType == HANDLE_TYPE_NCP_SERVER );
|
|
}
|
|
|
|
//
|
|
// Check to see if object is either a Server, Directory Map, or Volume.
|
|
// If so, the object is a known leaf in terms of NDS, and therefore cannot
|
|
// be enumerated through NwNdsList API calls. We fail the OpenEnum call in these
|
|
// cases and pass back the type of object the leaf node was. This way the code in
|
|
// NWPROVAU!NPOpenEnum can call NwrOpenEnumServer, NwrOpenEnumVolume, or
|
|
// NwrOpenEnumDirectories accordingly.
|
|
//
|
|
{
|
|
BYTE RawResponse[TWO_KB];
|
|
DWORD RawResponseSize = sizeof(RawResponse);
|
|
DWORD dwStrLen;
|
|
PBYTE pbRawGetInfo;
|
|
|
|
ntstatus = NwNdsReadObjectInfo( ContextHandle->TreeConnectionHandle,
|
|
ContextHandle->dwOid,
|
|
RawResponse,
|
|
RawResponseSize );
|
|
|
|
if ( ntstatus != NO_ERROR )
|
|
{
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
(void) NwRevertToSelf() ;
|
|
fImpersonate = FALSE;
|
|
|
|
pbRawGetInfo = RawResponse;
|
|
|
|
//
|
|
// The structure of a NDS_RESPONSE_GET_OBJECT_INFO consists of 4 DWORDs
|
|
// followed by two standard NDS format UNICODE strings. Below we jump pbRawGetInfo
|
|
// into the buffer, past the 4 DWORDs.
|
|
//
|
|
pbRawGetInfo += sizeof ( NDS_RESPONSE_GET_OBJECT_INFO );
|
|
|
|
//
|
|
// Now we get the length of the first string (Base Class).
|
|
//
|
|
dwStrLen = * ( DWORD * ) pbRawGetInfo;
|
|
|
|
//
|
|
// Now we point pbRawGetInfo to the first WCHAR of the first string (Base Class).
|
|
//
|
|
pbRawGetInfo += sizeof( DWORD );
|
|
|
|
//
|
|
// If the object is either a NCP Server, Volume, or a Directory Map, we fail
|
|
// the OpenEnum call and return the class type of the NDS leaf object. We do
|
|
// this because we cannot enumerate through NwNdsList() calls any subordinates,
|
|
// all browsing below these types are done through system redirector calls. So
|
|
// the client side of the provider will instead call NwOpenEnumVolumes or
|
|
// NwOpenEnumDirectories, respectively.
|
|
//
|
|
if ( !wcscmp( (LPWSTR) pbRawGetInfo, L"NCP Server" ) )
|
|
{
|
|
if ( ClassTypeOfNDSLeaf )
|
|
*ClassTypeOfNDSLeaf = CLASS_TYPE_NCP_SERVER;
|
|
status = ERROR_NETWORK_ACCESS_DENIED;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if ( !wcscmp( (LPWSTR) pbRawGetInfo, L"Volume" ) )
|
|
{
|
|
if ( ClassTypeOfNDSLeaf )
|
|
*ClassTypeOfNDSLeaf = CLASS_TYPE_VOLUME;
|
|
status = ERROR_NETWORK_ACCESS_DENIED;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if ( !wcscmp( (LPWSTR) pbRawGetInfo, L"Directory Map" ) )
|
|
{
|
|
if ( ClassTypeOfNDSLeaf )
|
|
*ClassTypeOfNDSLeaf = CLASS_TYPE_DIRECTORY_MAP;
|
|
status = ERROR_NETWORK_ACCESS_DENIED;
|
|
goto ErrorExit;
|
|
}
|
|
} // End of block
|
|
}
|
|
else // EnumType is something other than a NDS Sub-tree
|
|
{
|
|
UNICODE_STRING TreeConnectStr;
|
|
|
|
TreeConnectStr.Buffer = NULL;
|
|
ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
|
|
|
|
wcscpy(ContextHandle->ContainerName, StrippedContainerName);
|
|
wcscat(ContextHandle->ContainerName, L"\\");
|
|
|
|
//
|
|
// Open a tree connection handle to \Device\NwRdr\ContainerName
|
|
//
|
|
status = NwCreateTreeConnectName( StrippedContainerName,
|
|
NULL,
|
|
&TreeConnectStr );
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
status = NwOpenCreateConnection( &TreeConnectStr,
|
|
UserName,
|
|
Password,
|
|
StrippedContainerName,
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE |
|
|
( ValidateUserFlag? FILE_WRITE_DATA : 0 ),
|
|
CreateDisposition,
|
|
CreateOptions,
|
|
RESOURCETYPE_DISK, // When connecting beyond servername
|
|
&ContextHandle->TreeConnectionHandle,
|
|
NULL );
|
|
|
|
(void) LocalFree((HLOCAL) TreeConnectStr.Buffer);
|
|
}
|
|
|
|
if (status == NO_ERROR)
|
|
{
|
|
VERSION_INFO vInfo;
|
|
|
|
if ( EnumType == NwsHandleListVolumes ||
|
|
EnumType == NwsHandleListVolumesQueues )
|
|
{
|
|
NWC_SERVER_INFO ServerInfo;
|
|
|
|
ServerInfo.hConn = ContextHandle->TreeConnectionHandle;
|
|
ServerInfo.ServerString.Length = 0;
|
|
ServerInfo.ServerString.MaximumLength = 0;
|
|
ServerInfo.ServerString.Buffer = NULL;
|
|
|
|
status = NWGetFileServerVersionInfo( (HANDLE) &ServerInfo,
|
|
&vInfo );
|
|
|
|
if ( status )
|
|
{
|
|
ContextHandle->dwMaxVolumes = NW_MAX_VOLUME_NUMBER;
|
|
status = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
ContextHandle->dwMaxVolumes = (DWORD) vInfo.maxVolumes;
|
|
|
|
if ( ContextHandle->dwMaxVolumes == 0 )
|
|
{
|
|
ContextHandle->dwMaxVolumes = NW_MAX_VOLUME_NUMBER;
|
|
}
|
|
}
|
|
}
|
|
|
|
(void) NwRevertToSelf() ;
|
|
fImpersonate = FALSE;
|
|
|
|
if ( StrippedContainerName )
|
|
{
|
|
(void) LocalFree((HLOCAL) StrippedContainerName);
|
|
StrippedContainerName = NULL;
|
|
}
|
|
|
|
//
|
|
// Return the newly created context.
|
|
//
|
|
*EnumHandle = (LPNWWKSTA_CONTEXT_HANDLE) ContextHandle;
|
|
|
|
return status;
|
|
}
|
|
|
|
ErrorExit:
|
|
|
|
if ( fImpersonate )
|
|
(void) NwRevertToSelf() ;
|
|
|
|
if ( StrippedContainerName )
|
|
{
|
|
(void) LocalFree((HLOCAL) StrippedContainerName);
|
|
}
|
|
|
|
if ( ContextHandle )
|
|
{
|
|
if ( ContextHandle->TreeConnectionHandle )
|
|
CloseHandle( ContextHandle->TreeConnectionHandle );
|
|
|
|
ContextHandle->Signature = 0x0BADBAD0;
|
|
|
|
(void) LocalFree((HLOCAL) ContextHandle);
|
|
}
|
|
|
|
*EnumHandle = NULL;
|
|
|
|
if (status == ERROR_NOT_CONNECTED)
|
|
{
|
|
//
|
|
// Object name not found. We should return path not found.
|
|
//
|
|
status = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrEnum(
|
|
IN NWWKSTA_CONTEXT_HANDLE EnumHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function
|
|
|
|
Arguments:
|
|
|
|
EnumHandle - Supplies a pointer to the context handle which identifies
|
|
what type of object we are enumerating and the string of the
|
|
container name to concatenate to the returned object.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes required to get the
|
|
first entry. This value is returned iff WN_MORE_DATA is
|
|
the return code, and Buffer is too small to even fit one
|
|
entry.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
NO_ERROR is returned as long as at least one entry was written
|
|
into Buffer but does not necessarily mean that it's the number
|
|
of EntriesRequested.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - At least one entry was written to output buffer,
|
|
irregardless of the number requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit a single entry.
|
|
|
|
WN_BAD_HANDLE - The specified enumeration handle is invalid.
|
|
|
|
--*/ // NwrEnum
|
|
{
|
|
DWORD status;
|
|
LPNW_ENUM_CONTEXT ContextHandle = (LPNW_ENUM_CONTEXT) EnumHandle;
|
|
BOOL fImpersonate = FALSE ;
|
|
|
|
if (ContextHandle->Signature != NW_HANDLE_SIGNATURE) {
|
|
return WN_BAD_HANDLE;
|
|
}
|
|
|
|
//
|
|
// Impersonate the client
|
|
//
|
|
if ((status = NwImpersonateClient()) != NO_ERROR)
|
|
{
|
|
goto CleanExit;
|
|
}
|
|
fImpersonate = TRUE ;
|
|
|
|
*EntriesRead = 0;
|
|
*BytesNeeded = 0;
|
|
|
|
RtlZeroMemory(Buffer, BufferSize);
|
|
|
|
switch (ContextHandle->HandleType) {
|
|
case NwsHandleListConnections:
|
|
if (!(ContextHandle->ConnectionType & CONNTYPE_SYMBOLIC))
|
|
{
|
|
status = NwEnumerateConnections(
|
|
&ContextHandle->ResumeId,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead,
|
|
ContextHandle->ConnectionType,
|
|
NULL
|
|
);
|
|
}
|
|
break;
|
|
|
|
case NwsHandleListContextInfo_Tree:
|
|
case NwsHandleListContextInfo_Server:
|
|
|
|
status = NwEnumContextInfo(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
break;
|
|
|
|
case NwsHandleListServersAndNdsTrees:
|
|
|
|
status = NwEnumServersAndNdsTrees(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
break;
|
|
|
|
case NwsHandleListVolumes:
|
|
|
|
status = NwEnumVolumes(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
break;
|
|
|
|
case NwsHandleListNdsSubTrees_Disk:
|
|
|
|
status = NwEnumNdsSubTrees_Disk(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
|
|
break;
|
|
|
|
case NwsHandleListNdsSubTrees_Print:
|
|
|
|
status = NwEnumNdsSubTrees_Print(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
|
|
break;
|
|
|
|
case NwsHandleListNdsSubTrees_Any:
|
|
|
|
status = NwEnumNdsSubTrees_Any(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
|
|
break;
|
|
|
|
case NwsHandleListQueues:
|
|
|
|
status = NwEnumQueues(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
break;
|
|
|
|
case NwsHandleListVolumesQueues:
|
|
|
|
status = NwEnumVolumesQueues(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
break;
|
|
|
|
case NwsHandleListDirectories:
|
|
|
|
status = NwEnumDirectories(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
|
|
break;
|
|
|
|
case NwsHandleListPrintServers:
|
|
|
|
status = NwEnumPrintServers(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
break;
|
|
|
|
case NwsHandleListPrintQueues:
|
|
|
|
status = NwEnumPrintQueues(
|
|
ContextHandle,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
);
|
|
break;
|
|
|
|
default:
|
|
KdPrint(("NWWORKSTATION: NwrEnum unexpected handle type %lu\n",
|
|
ContextHandle->HandleType));
|
|
ASSERT(FALSE);
|
|
status = WN_BAD_HANDLE;
|
|
goto CleanExit ;
|
|
}
|
|
|
|
if (*EntriesRead > 0) {
|
|
|
|
switch ( ContextHandle->HandleType ) {
|
|
case NwsHandleListConnections:
|
|
case NwsHandleListContextInfo_Tree:
|
|
case NwsHandleListContextInfo_Server:
|
|
case NwsHandleListServersAndNdsTrees:
|
|
case NwsHandleListVolumes:
|
|
case NwsHandleListQueues:
|
|
case NwsHandleListVolumesQueues:
|
|
case NwsHandleListDirectories:
|
|
case NwsHandleListNdsSubTrees_Disk:
|
|
case NwsHandleListNdsSubTrees_Any:
|
|
{
|
|
DWORD i;
|
|
LPNETRESOURCEW NetR = (LPNETRESOURCEW) Buffer;
|
|
|
|
//
|
|
// Replace pointers to strings with offsets as need
|
|
//
|
|
|
|
if ((ContextHandle->HandleType == NwsHandleListConnections)
|
|
&& (ContextHandle->ConnectionType & CONNTYPE_SYMBOLIC))
|
|
{
|
|
//
|
|
// NwrEnumGWDevices already return offsets.
|
|
//
|
|
break ;
|
|
}
|
|
|
|
for (i = 0; i < *EntriesRead; i++, NetR++) {
|
|
|
|
if (NetR->lpLocalName != NULL) {
|
|
NetR->lpLocalName = (LPWSTR)
|
|
((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) Buffer);
|
|
}
|
|
|
|
NetR->lpRemoteName =
|
|
(LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR)Buffer);
|
|
|
|
if (NetR->lpComment != NULL) {
|
|
NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) -
|
|
(DWORD_PTR) Buffer);
|
|
}
|
|
|
|
if (NetR->lpProvider != NULL) {
|
|
NetR->lpProvider =
|
|
(LPWSTR) ((DWORD_PTR) (NetR->lpProvider) -
|
|
(DWORD_PTR) Buffer);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case NwsHandleListPrintServers:
|
|
case NwsHandleListPrintQueues:
|
|
case NwsHandleListNdsSubTrees_Print:
|
|
{
|
|
DWORD i;
|
|
PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) Buffer;
|
|
|
|
//
|
|
// Sort the entries in the buffer
|
|
//
|
|
if ( *EntriesRead > 1 )
|
|
qsort( Buffer, *EntriesRead,
|
|
sizeof( PRINTER_INFO_1W ), SortFunc );
|
|
|
|
//
|
|
// Replace pointers to strings with offsets
|
|
//
|
|
for (i = 0; i < *EntriesRead; i++, pPrinterInfo1++) {
|
|
|
|
MarshallDownStructure( (LPBYTE) pPrinterInfo1,
|
|
PrinterInfo1Offsets,
|
|
Buffer );
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
KdPrint(("NWWORKSTATION: NwrEnum (pointer to offset code) unexpected handle type %lu\n", ContextHandle->HandleType));
|
|
ASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
CleanExit:
|
|
|
|
if (fImpersonate)
|
|
(void) NwRevertToSelf() ;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrEnumConnections(
|
|
IN NWWKSTA_CONTEXT_HANDLE EnumHandle,
|
|
IN DWORD EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead,
|
|
IN DWORD fImplicitConnections
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is an alternate to NwrEnum. It only accepts handles
|
|
that are opened with ListConnections. This function takes a flag
|
|
indicating whether we need to show all implicit connections or not.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes required to get the
|
|
first entry. This value is returned iff ERROR_MORE_DATA is
|
|
the return code, and Buffer is too small to even fit one
|
|
entry.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
NO_ERROR is returned as long as at least one entry was written
|
|
into Buffer but does not necessarily mean that it's the number
|
|
of EntriesRequested.
|
|
|
|
fImplicitConnections - TRUE if we also want to get implicit connections,
|
|
FALSE otherwise.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - At least one entry was written to output buffer,
|
|
irregardless of the number requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
ERROR_MORE_DATA - The buffer was too small to fit a single entry.
|
|
|
|
--*/ // NwrEnumConnections
|
|
{
|
|
DWORD status;
|
|
LPNW_ENUM_CONTEXT ContextHandle = (LPNW_ENUM_CONTEXT) EnumHandle;
|
|
|
|
if ( (ContextHandle->Signature != NW_HANDLE_SIGNATURE)
|
|
|| ( ContextHandle->HandleType != NwsHandleListConnections )
|
|
)
|
|
{
|
|
return WN_BAD_HANDLE;
|
|
}
|
|
|
|
*EntriesRead = 0;
|
|
*BytesNeeded = 0;
|
|
|
|
RtlZeroMemory(Buffer, BufferSize);
|
|
|
|
if ( fImplicitConnections )
|
|
ContextHandle->ConnectionType |= CONNTYPE_IMPLICIT;
|
|
|
|
if ((status = NwImpersonateClient()) != NO_ERROR)
|
|
goto ErrorExit;
|
|
|
|
status = NwEnumerateConnections(
|
|
&ContextHandle->ResumeId,
|
|
EntriesRequested,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead,
|
|
ContextHandle->ConnectionType,
|
|
NULL
|
|
);
|
|
|
|
if (*EntriesRead > 0) {
|
|
|
|
//
|
|
// Replace pointers to strings with offsets
|
|
//
|
|
|
|
DWORD i;
|
|
LPNETRESOURCEW NetR = (LPNETRESOURCEW) Buffer;
|
|
|
|
for (i = 0; i < *EntriesRead; i++, NetR++) {
|
|
|
|
if (NetR->lpLocalName != NULL) {
|
|
NetR->lpLocalName = (LPWSTR)
|
|
((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) Buffer);
|
|
}
|
|
|
|
NetR->lpRemoteName =
|
|
(LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR)Buffer);
|
|
|
|
if (NetR->lpComment != NULL) {
|
|
NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) -
|
|
(DWORD_PTR) Buffer);
|
|
}
|
|
|
|
if (NetR->lpProvider != NULL) {
|
|
NetR->lpProvider = (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) -
|
|
(DWORD_PTR) Buffer);
|
|
}
|
|
}
|
|
}
|
|
(void) NwRevertToSelf();
|
|
|
|
ErrorExit:
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwEnumContextInfo(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates all of the bindery servers that are currently
|
|
connected, then sets the context handle so that the next NPEnumResource
|
|
call goes to the NDS subtree for the user's NDS context information
|
|
(if using NDS).
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes required to get the
|
|
first entry. This value is returned iff WN_MORE_DATA is
|
|
the return code, and Buffer is too small to even fit one
|
|
entry.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
NO_ERROR is returned as long as at least one entry was written
|
|
into Buffer but does not necessarily mean that it's the number
|
|
of EntriesRequested.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - At least one entry was written to output buffer,
|
|
irregardless of the number requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit a single entry.
|
|
|
|
--*/ // NwEnumContextInfo
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
DWORD_PTR tempResumeId = 0;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
BOOL FitInBuffer = TRUE;
|
|
DWORD EntrySize;
|
|
DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
|
|
|
|
while ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NON_NDS &&
|
|
FitInBuffer &&
|
|
EntriesRequested > *EntriesRead &&
|
|
status == NO_ERROR )
|
|
{
|
|
tempResumeId = ContextHandle->ResumeId;
|
|
|
|
status = NwGetNextServerConnection( ContextHandle );
|
|
|
|
if ( status == NO_ERROR && ContextHandle->ResumeId != 0 )
|
|
{
|
|
//
|
|
// Pack bindery server name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
L"\\\\",
|
|
NULL,
|
|
(LPWSTR) ContextHandle->ResumeId, // A server name
|
|
RESOURCE_CONTEXT,
|
|
RESOURCEDISPLAYTYPE_SERVER,
|
|
RESOURCEUSAGE_CONTAINER,
|
|
RESOURCETYPE_ANY,
|
|
NULL,
|
|
NULL,
|
|
&EntrySize
|
|
);
|
|
|
|
if (status == WN_MORE_DATA)
|
|
{
|
|
//
|
|
// Could not write current entry into output buffer,
|
|
// backup ResumeId to previous entry.
|
|
//
|
|
ContextHandle->ResumeId = tempResumeId;
|
|
ContextHandle->NdsRawDataCount += 1;
|
|
|
|
if (*EntriesRead)
|
|
{
|
|
//
|
|
// Still return success because we got at least one.
|
|
//
|
|
status = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
*BytesNeeded = EntrySize;
|
|
}
|
|
|
|
FitInBuffer = FALSE;
|
|
}
|
|
else if (status == NO_ERROR)
|
|
{
|
|
//
|
|
// Note that we've returned the current entry.
|
|
//
|
|
(*EntriesRead)++;
|
|
}
|
|
}
|
|
else if ( status == WN_NO_MORE_ENTRIES )
|
|
{
|
|
//
|
|
// We processed the last item in list, so
|
|
// start enumerating servers.
|
|
//
|
|
ContextHandle->ResumeId = 0;
|
|
LastObjectId = 0;
|
|
|
|
if ( ContextHandle->HandleType == NwsHandleListContextInfo_Tree )
|
|
{
|
|
ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NDS;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NDS )
|
|
{
|
|
ContextHandle->HandleType = NwsHandleListNdsSubTrees_Any;
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// User asked for more than there are entries. We just say that
|
|
// all is well.
|
|
//
|
|
// This is incompliance with the wierd provider API definition where
|
|
// if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
|
|
// at least one entry fit into output buffer, there's no telling if
|
|
// the buffer was too small for more entries or there are no more
|
|
// entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
|
|
// before knowing that the last call had actually reached the end of list.
|
|
//
|
|
if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
|
|
{
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwEnumServersAndNdsTrees(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates all the servers and NDS trees on the local
|
|
network by: 1) scanning the bindery for file server objects on the
|
|
preferred server and 2) scanning the bindery for directory servers
|
|
(NDS trees) on the preferred server. The server and tree entries are
|
|
returned in an array of NETRESOURCE entries; each servername is
|
|
prefixed by \\.
|
|
|
|
The ContextHandle->ResumeId field is initially -1 before
|
|
enumeration begins and contains the object ID of the last server
|
|
or NDS tree object returned, depending on the value of
|
|
ContextHandle->dwUsingNds.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes required to get the
|
|
first entry. This value is returned iff WN_MORE_DATA is
|
|
the return code, and Buffer is too small to even fit one
|
|
entry.
|
|
|
|
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
NO_ERROR is returned as long as at least one entry was written
|
|
into Buffer but does not necessarily mean that it's the number
|
|
of EntriesRequested.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - At least one entry was written to output buffer,
|
|
irregardless of the number requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit a single entry.
|
|
|
|
--*/ // NwEnumServersAndNdsTrees
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
DWORD_PTR tempResumeId = 0;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
BOOL FitInBuffer = TRUE;
|
|
DWORD EntrySize;
|
|
|
|
SERVERNAME ServerName; // OEM server name
|
|
LPWSTR UServerName = NULL; // Unicode server name
|
|
DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
|
|
|
|
while ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NDS &&
|
|
FitInBuffer &&
|
|
EntriesRequested > *EntriesRead &&
|
|
status == NO_ERROR )
|
|
{
|
|
tempResumeId = ContextHandle->ResumeId;
|
|
|
|
//
|
|
// Call the scan bindery object NCP to scan for all NDS
|
|
// tree objects.
|
|
//
|
|
status = NwGetNextNdsTreeEntry( ContextHandle );
|
|
|
|
if ( status == NO_ERROR && ContextHandle->ResumeId != 0 )
|
|
{
|
|
//
|
|
// Pack tree name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
L"\\\\",
|
|
NULL,
|
|
(LPWSTR) ContextHandle->ResumeId, // This is a NDS tree name
|
|
RESOURCE_GLOBALNET,
|
|
RESOURCEDISPLAYTYPE_TREE,
|
|
RESOURCEUSAGE_CONTAINER,
|
|
RESOURCETYPE_ANY,
|
|
NULL,
|
|
NULL,
|
|
&EntrySize
|
|
);
|
|
|
|
if (status == WN_MORE_DATA)
|
|
{
|
|
//
|
|
// Could not write current entry into output buffer, backup ResumeId to
|
|
// previous entry.
|
|
//
|
|
ContextHandle->ResumeId = tempResumeId;
|
|
ContextHandle->NdsRawDataCount += 1;
|
|
|
|
if (*EntriesRead)
|
|
{
|
|
//
|
|
// Still return success because we got at least one.
|
|
//
|
|
status = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
*BytesNeeded = EntrySize;
|
|
}
|
|
|
|
FitInBuffer = FALSE;
|
|
}
|
|
else if (status == NO_ERROR)
|
|
{
|
|
//
|
|
// Note that we've returned the current entry.
|
|
//
|
|
(*EntriesRead)++;
|
|
}
|
|
}
|
|
else if ( status == WN_NO_MORE_ENTRIES )
|
|
{
|
|
//
|
|
// We processed the last item in list, so
|
|
// start enumerating servers.
|
|
//
|
|
ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
|
|
ContextHandle->ResumeId = (DWORD_PTR) -1;
|
|
LastObjectId = (DWORD) -1;
|
|
}
|
|
}
|
|
|
|
if ( status == WN_NO_MORE_ENTRIES)
|
|
{
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
while ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NON_NDS &&
|
|
FitInBuffer &&
|
|
EntriesRequested > *EntriesRead &&
|
|
status == NO_ERROR )
|
|
{
|
|
RtlZeroMemory(ServerName, sizeof(ServerName));
|
|
|
|
//
|
|
// Call the scan bindery object NCP to scan for all file
|
|
// server objects.
|
|
//
|
|
status = NwGetNextServerEntry(
|
|
ContextHandle->TreeConnectionHandle,
|
|
&LastObjectId,
|
|
ServerName
|
|
);
|
|
|
|
if (status == NO_ERROR && NwConvertToUnicode(&UServerName, ServerName))
|
|
{
|
|
//
|
|
// Pack server name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
L"\\\\",
|
|
NULL,
|
|
UServerName,
|
|
RESOURCE_GLOBALNET,
|
|
RESOURCEDISPLAYTYPE_SERVER,
|
|
RESOURCEUSAGE_CONTAINER,
|
|
RESOURCETYPE_ANY,
|
|
NULL,
|
|
NULL,
|
|
&EntrySize
|
|
);
|
|
|
|
if (status == WN_MORE_DATA)
|
|
{
|
|
//
|
|
// Could not write current entry into output buffer.
|
|
//
|
|
|
|
if (*EntriesRead)
|
|
{
|
|
//
|
|
// Still return success because we got at least one.
|
|
//
|
|
status = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
*BytesNeeded = EntrySize;
|
|
}
|
|
|
|
FitInBuffer = FALSE;
|
|
}
|
|
else if (status == NO_ERROR)
|
|
{
|
|
//
|
|
// Note that we've returned the current entry.
|
|
//
|
|
(*EntriesRead)++;
|
|
|
|
ContextHandle->ResumeId = (DWORD_PTR) LastObjectId;
|
|
}
|
|
|
|
(void) LocalFree((HLOCAL) UServerName);
|
|
}
|
|
}
|
|
|
|
//
|
|
// User asked for more than there are entries. We just say that
|
|
// all is well.
|
|
//
|
|
// This is incompliance with the wierd provider API definition where
|
|
// if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
|
|
// at least one entry fit into output buffer, there's no telling if
|
|
// the buffer was too small for more entries or there are no more
|
|
// entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
|
|
// before knowing that the last call had actually reached the end of list.
|
|
//
|
|
if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
|
|
{
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NwEnumVolumes(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates all the volumes on a server by
|
|
iteratively getting the volume name for each volume number from
|
|
0 - 31 until we run into the first volume number that does not
|
|
map to a volume name (this method assumes that volume numbers
|
|
are used contiguously in ascending order). The volume entries
|
|
are returned in an array of NETRESOURCE entries; each volume
|
|
name if prefixed by \\Server\.
|
|
|
|
The ContextHandle->ResumeId field always indicates the next
|
|
volume entry to return. It is initially set to 0, which indicates
|
|
the first volume number to get.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes required to get the
|
|
first entry. This value is returned iff WN_MORE_DATA is
|
|
the return code, and Buffer is too small to even fit one
|
|
entry.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
NO_ERROR is returned as long as at least one entry was written
|
|
into Buffer but does not necessarily mean that it's the number
|
|
of EntriesRequested.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - At least one entry was written to output buffer,
|
|
irregardless of the number requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit a single entry.
|
|
|
|
--*/ // NwEnumVolumes
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
BOOL FitInBuffer = TRUE;
|
|
DWORD EntrySize;
|
|
|
|
CHAR VolumeName[NW_VOLUME_NAME_LEN]; // OEM volume name
|
|
LPWSTR UVolumeName = NULL; // Unicode volume name
|
|
DWORD NextVolumeNumber = (DWORD) ContextHandle->ResumeId;
|
|
DWORD MaxVolumeNumber = ContextHandle->dwMaxVolumes;
|
|
ULONG Failures = 0;
|
|
|
|
if (NextVolumeNumber == MaxVolumeNumber) {
|
|
//
|
|
// Reached the end of enumeration
|
|
//
|
|
return WN_NO_MORE_ENTRIES;
|
|
}
|
|
|
|
while (FitInBuffer &&
|
|
EntriesRequested > *EntriesRead &&
|
|
NextVolumeNumber < MaxVolumeNumber &&
|
|
status == NO_ERROR) {
|
|
|
|
RtlZeroMemory(VolumeName, sizeof(VolumeName));
|
|
|
|
//
|
|
// Call the scan bindery object NCP to scan for all file
|
|
// volume objects.
|
|
//
|
|
|
|
status = NwGetNextVolumeEntry(
|
|
ContextHandle->TreeConnectionHandle,
|
|
NextVolumeNumber++,
|
|
VolumeName
|
|
);
|
|
|
|
if (status == NO_ERROR) {
|
|
|
|
if (VolumeName[0] == 0) {
|
|
|
|
//
|
|
// Got an empty volume name back for the next volume number
|
|
// which indicates there is no volume associated with the
|
|
// volume number but still got error success.
|
|
//
|
|
// Treat this as having reached the end of the enumeration
|
|
// only if we've gotten two three empty volumes in a row
|
|
// or reached the max number of volumes because there are
|
|
// some cases where there are holes in the way that volumes
|
|
// are allocated.
|
|
//
|
|
|
|
Failures++;
|
|
|
|
if ( Failures <= 3 ) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
NextVolumeNumber = MaxVolumeNumber;
|
|
ContextHandle->ResumeId = MaxVolumeNumber;
|
|
|
|
if (*EntriesRead == 0) {
|
|
status = WN_NO_MORE_ENTRIES;
|
|
}
|
|
}
|
|
|
|
} else if (NwConvertToUnicode(&UVolumeName, VolumeName)) {
|
|
|
|
//
|
|
// Pack volume name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
ContextHandle->ContainerName,
|
|
NULL,
|
|
UVolumeName,
|
|
RESOURCE_GLOBALNET,
|
|
RESOURCEDISPLAYTYPE_SHARE,
|
|
#ifdef NT1057
|
|
RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_CONTAINER,
|
|
#else
|
|
RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_NOLOCALDEVICE,
|
|
#endif
|
|
RESOURCETYPE_DISK,
|
|
NULL,
|
|
NULL,
|
|
&EntrySize
|
|
);
|
|
|
|
if (status == WN_MORE_DATA) {
|
|
|
|
//
|
|
// Could not write current entry into output buffer.
|
|
//
|
|
|
|
if (*EntriesRead) {
|
|
//
|
|
// Still return success because we got at least one.
|
|
//
|
|
status = NO_ERROR;
|
|
}
|
|
else {
|
|
*BytesNeeded = EntrySize;
|
|
}
|
|
|
|
FitInBuffer = FALSE;
|
|
}
|
|
else if (status == NO_ERROR) {
|
|
|
|
//
|
|
// Note that we've returned the current entry.
|
|
//
|
|
(*EntriesRead)++;
|
|
|
|
ContextHandle->ResumeId = NextVolumeNumber;
|
|
}
|
|
|
|
(void) LocalFree((HLOCAL) UVolumeName);
|
|
}
|
|
|
|
//
|
|
// We got an entry, so reset the failure counter.
|
|
//
|
|
|
|
Failures = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// User asked for more than there are entries. We just say that
|
|
// all is well.
|
|
//
|
|
// This is incompliance with the wierd provider API definition where
|
|
// if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
|
|
// at least one entry fit into output buffer, there's no telling if
|
|
// the buffer was too small for more entries or there are no more
|
|
// entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
|
|
// before knowing that the last call had actually reached the end of list.
|
|
//
|
|
if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwEnumNdsSubTrees_Disk(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates the sub-trees of a given NDS tree
|
|
handle. It returns the fully-qualified UNC path of the sub-tree
|
|
entries in an array of NETRESOURCE entries.
|
|
|
|
The ContextHandle->ResumeId field is 0 initially, and contains
|
|
a pointer to the subtree name string of the last sub-tree
|
|
returned. If there are no more sub-trees to return, this
|
|
field is set to -1.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle. It contains
|
|
an opened NDS tree handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes required to get the
|
|
first entry. This value is returned iff WN_MORE_DATA is
|
|
the return code, and Buffer is too small to even fit one
|
|
entry.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
NO_ERROR is returned as long as at least one entry was written
|
|
into Buffer but does not necessarily mean that it's the number
|
|
of EntriesRequested.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - At least one entry was written to output buffer,
|
|
irregardless of the number requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit a single entry.
|
|
|
|
--*/ // NwEnumNdsSubTrees_Disk
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
BOOL FitInBuffer = TRUE;
|
|
DWORD EntrySize = 0;
|
|
|
|
LPWSTR SubTreeName = NULL;
|
|
DWORD ResourceScope = 0;
|
|
DWORD ResourceType = 0;
|
|
DWORD ResourceDisplayType = 0;
|
|
DWORD ResourceUsage = 0;
|
|
LPWSTR StrippedObjectName = NULL;
|
|
|
|
if (ContextHandle->ResumeId == (DWORD_PTR) -1)
|
|
{
|
|
//
|
|
// Reached the end of enumeration.
|
|
//
|
|
return WN_NO_MORE_ENTRIES;
|
|
}
|
|
|
|
while (FitInBuffer &&
|
|
EntriesRequested > *EntriesRead &&
|
|
status == NO_ERROR)
|
|
{
|
|
if ( ContextHandle->ResumeId == 0 )
|
|
{
|
|
//
|
|
// Get the first subtree entry.
|
|
//
|
|
status = NwGetFirstNdsSubTreeEntry( ContextHandle, BufferSize );
|
|
}
|
|
|
|
//
|
|
// Either ResumeId contains the first entry we just got from
|
|
// NwGetFirstDirectoryEntry or it contains the next directory
|
|
// entry to return.
|
|
//
|
|
if (status == NO_ERROR && ContextHandle->ResumeId != 0)
|
|
{
|
|
BYTE ClassType;
|
|
LPWSTR newPathStr = NULL;
|
|
LPWSTR tempStr = NULL;
|
|
WORD tempStrLen;
|
|
|
|
//
|
|
// Get current subtree data from ContextHandle
|
|
//
|
|
ClassType = NwGetSubTreeData( ContextHandle->ResumeId,
|
|
&SubTreeName,
|
|
&ResourceScope,
|
|
&ResourceType,
|
|
&ResourceDisplayType,
|
|
&ResourceUsage,
|
|
&StrippedObjectName );
|
|
|
|
if ( StrippedObjectName == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Disk LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
switch( ClassType )
|
|
{
|
|
case CLASS_TYPE_COUNTRY:
|
|
case CLASS_TYPE_DIRECTORY_MAP:
|
|
case CLASS_TYPE_NCP_SERVER:
|
|
case CLASS_TYPE_ORGANIZATION:
|
|
case CLASS_TYPE_ORGANIZATIONAL_UNIT:
|
|
case CLASS_TYPE_VOLUME:
|
|
|
|
//
|
|
// Need to build a string with the new NDS UNC path for subtree object
|
|
//
|
|
newPathStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
|
|
( wcslen( StrippedObjectName ) +
|
|
wcslen( ContextHandle->ContainerName ) +
|
|
3 ) * sizeof(WCHAR) );
|
|
|
|
if ( newPathStr == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Disk LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
|
|
ContextHandle->ContainerName,
|
|
PARSE_NDS_GET_TREE_NAME );
|
|
|
|
tempStrLen /= sizeof( WCHAR );
|
|
|
|
if ( tempStrLen > 0 )
|
|
{
|
|
wcscpy( newPathStr, L"\\\\" );
|
|
wcsncat( newPathStr, tempStr, tempStrLen );
|
|
wcscat( newPathStr, L"\\" );
|
|
wcscat( newPathStr, StrippedObjectName );
|
|
}
|
|
|
|
(void) LocalFree((HLOCAL) StrippedObjectName );
|
|
StrippedObjectName = NULL;
|
|
|
|
tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
|
|
ContextHandle->ContainerName,
|
|
PARSE_NDS_GET_PATH_NAME );
|
|
|
|
tempStrLen /= sizeof( WCHAR );
|
|
|
|
if ( tempStrLen > 0 )
|
|
{
|
|
wcscat( newPathStr, L"." );
|
|
wcsncat( newPathStr, tempStr, tempStrLen );
|
|
}
|
|
|
|
//
|
|
// Pack subtree name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
NULL,
|
|
NULL,
|
|
newPathStr,
|
|
ResourceScope,
|
|
ResourceDisplayType,
|
|
ResourceUsage,
|
|
ResourceType,
|
|
NULL,
|
|
NULL,
|
|
&EntrySize );
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
//
|
|
// Note that we've returned the current entry.
|
|
//
|
|
(*EntriesRead)++;
|
|
}
|
|
|
|
if ( newPathStr )
|
|
(void) LocalFree( (HLOCAL) newPathStr );
|
|
|
|
break;
|
|
|
|
case CLASS_TYPE_ALIAS:
|
|
case CLASS_TYPE_AFP_SERVER:
|
|
case CLASS_TYPE_BINDERY_OBJECT:
|
|
case CLASS_TYPE_BINDERY_QUEUE:
|
|
case CLASS_TYPE_COMPUTER:
|
|
case CLASS_TYPE_GROUP:
|
|
case CLASS_TYPE_LOCALITY:
|
|
case CLASS_TYPE_ORGANIZATIONAL_ROLE:
|
|
case CLASS_TYPE_PRINTER:
|
|
case CLASS_TYPE_PRINT_SERVER:
|
|
case CLASS_TYPE_PROFILE:
|
|
case CLASS_TYPE_QUEUE:
|
|
case CLASS_TYPE_TOP:
|
|
case CLASS_TYPE_UNKNOWN:
|
|
case CLASS_TYPE_USER:
|
|
break;
|
|
|
|
default:
|
|
KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Disk - Unhandled switch statement case %lu\n", ClassType ));
|
|
ASSERT( FALSE );
|
|
break;
|
|
}
|
|
|
|
if (status == WN_MORE_DATA)
|
|
{
|
|
//
|
|
// Could not write current entry into output buffer.
|
|
//
|
|
|
|
if (*EntriesRead)
|
|
{
|
|
//
|
|
// Still return success because we got at least one.
|
|
//
|
|
status = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
*BytesNeeded = EntrySize;
|
|
}
|
|
|
|
FitInBuffer = FALSE;
|
|
}
|
|
else if (status == NO_ERROR)
|
|
{
|
|
//
|
|
// Get next directory entry.
|
|
//
|
|
status = NwGetNextNdsSubTreeEntry( ContextHandle );
|
|
}
|
|
}
|
|
|
|
if (status == WN_NO_MORE_ENTRIES)
|
|
{
|
|
ContextHandle->ResumeId = (DWORD_PTR) -1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// User asked for more than there are entries. We just say that
|
|
// all is well.
|
|
//
|
|
// This is incompliance with the wierd provider API definition where
|
|
// if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
|
|
// at least one entry fit into output buffer, there's no telling if
|
|
// the buffer was too small for more entries or there are no more
|
|
// entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
|
|
// before knowing that the last call had actually reached the end of list.
|
|
//
|
|
if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM)
|
|
{
|
|
KdPrint(("NwEnumNdsSubTrees_Disk returns %lu\n", status));
|
|
}
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwEnumNdsSubTrees_Print(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates all the NDS subtree objects that are either containers,
|
|
queues, printers, or servers from a given NDS tree or subtree. The entries are
|
|
returned in an array of PRINTER_INFO_1 entries and each name is prefixed
|
|
by the parent path in NDS UNC style (ex. \\tree\CN=foo.OU=bar.O=blah).
|
|
|
|
The ContextHandle->ResumeId field is initially (DWORD_PTR) -1 before
|
|
enumeration begins and contains the object ID of the last NDS object returned.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is (DWORD_PTR) -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes copied or required to get all
|
|
the requested entries.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - Buffer contains all the entries requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit the requested entries.
|
|
|
|
--*/ // NwEnumNdsSubTrees_Print
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
DWORD EntrySize;
|
|
BOOL FitInBuffer = TRUE;
|
|
|
|
LPWSTR SubTreeName = NULL;
|
|
DWORD ResourceScope = 0;
|
|
DWORD ResourceType = 0;
|
|
DWORD ResourceDisplayType = 0;
|
|
DWORD ResourceUsage = 0;
|
|
LPWSTR StrippedObjectName = NULL;
|
|
BYTE ClassType = 0;
|
|
LPWSTR newPathStr = NULL;
|
|
LPWSTR tempStr = NULL;
|
|
WORD tempStrLen = 0;
|
|
|
|
while ( EntriesRequested > *EntriesRead &&
|
|
( (status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER)))
|
|
{
|
|
if (ContextHandle->ResumeId == 0)
|
|
{
|
|
//
|
|
// Get the first subtree entry.
|
|
//
|
|
status = NwGetFirstNdsSubTreeEntry( ContextHandle, BufferSize );
|
|
}
|
|
|
|
//
|
|
// Either ResumeId contains the first entry we just got from
|
|
// NwGetFirstDirectoryEntry or it contains the next directory
|
|
// entry to return.
|
|
//
|
|
if (status == NO_ERROR && ContextHandle->ResumeId != 0)
|
|
{
|
|
|
|
//
|
|
// Get current subtree data from ContextHandle
|
|
//
|
|
ClassType = NwGetSubTreeData( ContextHandle->ResumeId,
|
|
&SubTreeName,
|
|
&ResourceScope,
|
|
&ResourceType,
|
|
&ResourceDisplayType,
|
|
&ResourceUsage,
|
|
&StrippedObjectName );
|
|
|
|
if ( StrippedObjectName == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
switch( ClassType )
|
|
{
|
|
|
|
case CLASS_TYPE_COUNTRY:
|
|
case CLASS_TYPE_ORGANIZATION:
|
|
case CLASS_TYPE_ORGANIZATIONAL_UNIT:
|
|
case CLASS_TYPE_NCP_SERVER:
|
|
case CLASS_TYPE_QUEUE:
|
|
//
|
|
// Need to build a string with the new NDS UNC path for subtree object
|
|
//
|
|
newPathStr = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
|
|
( wcslen( StrippedObjectName ) +
|
|
wcslen( ContextHandle->ContainerName ) +
|
|
2 ) * sizeof(WCHAR) );
|
|
|
|
if ( newPathStr == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
|
|
ContextHandle->ContainerName,
|
|
PARSE_NDS_GET_TREE_NAME );
|
|
|
|
tempStrLen /= sizeof( WCHAR );
|
|
|
|
if ( tempStrLen > 0 )
|
|
{
|
|
wcsncpy( newPathStr, tempStr, tempStrLen );
|
|
wcscat( newPathStr, L"\\" );
|
|
wcscat( newPathStr, StrippedObjectName );
|
|
}
|
|
|
|
(void) LocalFree((HLOCAL) StrippedObjectName );
|
|
StrippedObjectName = NULL;
|
|
|
|
tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
|
|
ContextHandle->ContainerName,
|
|
PARSE_NDS_GET_PATH_NAME );
|
|
|
|
tempStrLen /= sizeof( WCHAR );
|
|
|
|
if ( tempStrLen > 0 )
|
|
{
|
|
wcscat( newPathStr, L"." );
|
|
wcsncat( newPathStr, tempStr, tempStrLen );
|
|
}
|
|
|
|
switch( ClassType )
|
|
{
|
|
case CLASS_TYPE_COUNTRY:
|
|
case CLASS_TYPE_ORGANIZATION:
|
|
case CLASS_TYPE_ORGANIZATIONAL_UNIT:
|
|
//
|
|
// Pack sub-tree container name into output buffer.
|
|
//
|
|
status = NwWritePrinterInfoEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
NULL,
|
|
newPathStr,
|
|
PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON1,
|
|
&EntrySize );
|
|
|
|
break;
|
|
|
|
case CLASS_TYPE_NCP_SERVER:
|
|
//
|
|
// Pack server name into output buffer.
|
|
//
|
|
status = NwWritePrinterInfoEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
NULL,
|
|
newPathStr,
|
|
PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON3,
|
|
&EntrySize );
|
|
|
|
break;
|
|
|
|
case CLASS_TYPE_QUEUE:
|
|
//
|
|
// Pack print server queue name into output buffer.
|
|
//
|
|
status = NwWritePrinterInfoEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
L"\\\\",
|
|
newPathStr,
|
|
PRINTER_ENUM_ICON8,
|
|
&EntrySize );
|
|
break;
|
|
|
|
default:
|
|
KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print - Unhandled switch statement case %lu\n", ClassType ));
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
switch ( status )
|
|
{
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
FitInBuffer = FALSE;
|
|
// Falls through
|
|
|
|
case NO_ERROR:
|
|
*BytesNeeded += EntrySize;
|
|
(*EntriesRead)++;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ( newPathStr )
|
|
(void) LocalFree( (HLOCAL) newPathStr );
|
|
|
|
break;
|
|
|
|
case CLASS_TYPE_ALIAS:
|
|
case CLASS_TYPE_AFP_SERVER:
|
|
case CLASS_TYPE_BINDERY_OBJECT:
|
|
case CLASS_TYPE_BINDERY_QUEUE:
|
|
case CLASS_TYPE_COMPUTER:
|
|
case CLASS_TYPE_DIRECTORY_MAP:
|
|
case CLASS_TYPE_GROUP:
|
|
case CLASS_TYPE_LOCALITY:
|
|
case CLASS_TYPE_ORGANIZATIONAL_ROLE:
|
|
case CLASS_TYPE_PRINTER:
|
|
case CLASS_TYPE_PRINT_SERVER:
|
|
case CLASS_TYPE_PROFILE:
|
|
case CLASS_TYPE_TOP:
|
|
case CLASS_TYPE_UNKNOWN:
|
|
case CLASS_TYPE_USER:
|
|
case CLASS_TYPE_VOLUME:
|
|
break;
|
|
|
|
default:
|
|
KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print - Unhandled switch statement case %lu\n", ClassType ));
|
|
ASSERT( FALSE );
|
|
break;
|
|
}
|
|
|
|
if ( status == NO_ERROR || status == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
//
|
|
// Get next directory entry.
|
|
//
|
|
status = NwGetNextNdsSubTreeEntry( ContextHandle );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is incompliance with the wierd provider API definition where
|
|
// if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
|
|
// at least one entry fit into output buffer, there's no telling if
|
|
// the buffer was too small for more entries or there are no more
|
|
// entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
|
|
// before knowing that the last call had actually reached the end of list.
|
|
//
|
|
if ( !FitInBuffer )
|
|
{
|
|
*EntriesRead = 0;
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
|
|
{
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwEnumNdsSubTrees_Any(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates the sub-trees of a given NDS tree
|
|
handle. It returns the fully-qualified UNC path of ANY sub-tree
|
|
entries in an array of NETRESOURCE entries.
|
|
|
|
The ContextHandle->ResumeId field is 0 initially, and contains
|
|
a pointer to the subtree name string of the last sub-tree
|
|
returned. If there are no more sub-trees to return, this
|
|
field is set to (DWORD_PTR) -1.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle. It contains
|
|
an opened NDS tree handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is (DWORD_PTR) -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes required to get the
|
|
first entry. This value is returned iff WN_MORE_DATA is
|
|
the return code, and Buffer is too small to even fit one
|
|
entry.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
NO_ERROR is returned as long as at least one entry was written
|
|
into Buffer but does not necessarily mean that it's the number
|
|
of EntriesRequested.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - At least one entry was written to output buffer,
|
|
irregardless of the number requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit a single entry.
|
|
|
|
--*/ // NwEnumNdsSubTrees_Any
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
BOOL FitInBuffer = TRUE;
|
|
DWORD EntrySize = 0;
|
|
|
|
LPWSTR SubTreeName = NULL;
|
|
DWORD ResourceScope = 0;
|
|
DWORD ResourceType = 0;
|
|
DWORD ResourceDisplayType = 0;
|
|
DWORD ResourceUsage = 0;
|
|
LPWSTR StrippedObjectName = NULL;
|
|
|
|
if (ContextHandle->ResumeId == (DWORD_PTR) -1)
|
|
{
|
|
//
|
|
// Reached the end of enumeration.
|
|
//
|
|
return WN_NO_MORE_ENTRIES;
|
|
}
|
|
|
|
while (FitInBuffer &&
|
|
EntriesRequested > *EntriesRead &&
|
|
status == NO_ERROR)
|
|
{
|
|
if ( ContextHandle->ResumeId == 0 )
|
|
{
|
|
//
|
|
// Get the first subtree entry.
|
|
//
|
|
status = NwGetFirstNdsSubTreeEntry( ContextHandle, BufferSize );
|
|
}
|
|
|
|
//
|
|
// Either ResumeId contains the first entry we just got from
|
|
// NwGetFirstDirectoryEntry or it contains the next directory
|
|
// entry to return.
|
|
//
|
|
if (status == NO_ERROR && ContextHandle->ResumeId != 0)
|
|
{
|
|
BYTE ClassType;
|
|
LPWSTR newPathStr = NULL;
|
|
LPWSTR tempStr = NULL;
|
|
WORD tempStrLen;
|
|
|
|
//
|
|
// Get current subtree data from ContextHandle
|
|
//
|
|
ClassType = NwGetSubTreeData( ContextHandle->ResumeId,
|
|
&SubTreeName,
|
|
&ResourceScope,
|
|
&ResourceType,
|
|
&ResourceDisplayType,
|
|
&ResourceUsage,
|
|
&StrippedObjectName );
|
|
|
|
if ( StrippedObjectName == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Any LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
switch( ClassType )
|
|
{
|
|
case CLASS_TYPE_COUNTRY:
|
|
case CLASS_TYPE_ORGANIZATION:
|
|
case CLASS_TYPE_ORGANIZATIONAL_UNIT:
|
|
case CLASS_TYPE_VOLUME:
|
|
case CLASS_TYPE_DIRECTORY_MAP:
|
|
case CLASS_TYPE_NCP_SERVER:
|
|
case CLASS_TYPE_QUEUE:
|
|
|
|
//
|
|
// Need to build a string with the new NDS UNC path for subtree object
|
|
//
|
|
newPathStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
|
|
( wcslen( StrippedObjectName ) +
|
|
wcslen( ContextHandle->ContainerName ) +
|
|
3 ) * sizeof(WCHAR) );
|
|
|
|
if ( newPathStr == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Any LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
|
|
ContextHandle->ContainerName,
|
|
PARSE_NDS_GET_TREE_NAME );
|
|
|
|
tempStrLen /= sizeof( WCHAR );
|
|
|
|
if ( tempStrLen > 0 )
|
|
{
|
|
wcscpy( newPathStr, L"\\\\" );
|
|
wcsncat( newPathStr, tempStr, tempStrLen );
|
|
wcscat( newPathStr, L"\\" );
|
|
wcscat( newPathStr, StrippedObjectName );
|
|
}
|
|
|
|
(void) LocalFree((HLOCAL) StrippedObjectName );
|
|
StrippedObjectName = NULL;
|
|
|
|
tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
|
|
ContextHandle->ContainerName,
|
|
PARSE_NDS_GET_PATH_NAME );
|
|
|
|
tempStrLen /= sizeof( WCHAR );
|
|
|
|
if ( tempStrLen > 0 )
|
|
{
|
|
wcscat( newPathStr, L"." );
|
|
wcsncat( newPathStr, tempStr, tempStrLen );
|
|
}
|
|
|
|
//
|
|
// Pack subtree name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
NULL,
|
|
NULL,
|
|
newPathStr,
|
|
ResourceScope,
|
|
ResourceDisplayType,
|
|
ResourceUsage,
|
|
ResourceType,
|
|
NULL,
|
|
NULL,
|
|
&EntrySize );
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
//
|
|
// Note that we've returned the current entry.
|
|
//
|
|
(*EntriesRead)++;
|
|
}
|
|
|
|
if ( newPathStr )
|
|
(void) LocalFree( (HLOCAL) newPathStr );
|
|
|
|
break;
|
|
|
|
case CLASS_TYPE_ALIAS:
|
|
case CLASS_TYPE_AFP_SERVER:
|
|
case CLASS_TYPE_BINDERY_OBJECT:
|
|
case CLASS_TYPE_BINDERY_QUEUE:
|
|
case CLASS_TYPE_COMPUTER:
|
|
case CLASS_TYPE_GROUP:
|
|
case CLASS_TYPE_LOCALITY:
|
|
case CLASS_TYPE_ORGANIZATIONAL_ROLE:
|
|
case CLASS_TYPE_PRINTER:
|
|
case CLASS_TYPE_PRINT_SERVER:
|
|
case CLASS_TYPE_PROFILE:
|
|
case CLASS_TYPE_TOP:
|
|
case CLASS_TYPE_UNKNOWN:
|
|
case CLASS_TYPE_USER:
|
|
break;
|
|
|
|
default:
|
|
KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Any - Unhandled switch statement case %lu\n", ClassType ));
|
|
ASSERT( FALSE );
|
|
break;
|
|
}
|
|
|
|
if (status == WN_MORE_DATA)
|
|
{
|
|
//
|
|
// Could not write current entry into output buffer.
|
|
//
|
|
|
|
if (*EntriesRead)
|
|
{
|
|
//
|
|
// Still return success because we got at least one.
|
|
//
|
|
status = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
*BytesNeeded = EntrySize;
|
|
}
|
|
|
|
FitInBuffer = FALSE;
|
|
}
|
|
else if (status == NO_ERROR)
|
|
{
|
|
//
|
|
// Get next directory entry.
|
|
//
|
|
status = NwGetNextNdsSubTreeEntry( ContextHandle );
|
|
}
|
|
}
|
|
|
|
if (status == WN_NO_MORE_ENTRIES)
|
|
{
|
|
ContextHandle->ResumeId = (DWORD_PTR) -1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// User asked for more than there are entries. We just say that
|
|
// all is well.
|
|
//
|
|
// This is incompliance with the wierd provider API definition where
|
|
// if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
|
|
// at least one entry fit into output buffer, there's no telling if
|
|
// the buffer was too small for more entries or there are no more
|
|
// entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
|
|
// before knowing that the last call had actually reached the end of list.
|
|
//
|
|
if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM)
|
|
{
|
|
KdPrint(("NwEnumNdsSubTrees_Any returns %lu\n", status));
|
|
}
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwEnumVolumesQueues(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates all the volumes and queues on a server.
|
|
The queue entries are returned in an array of NETRESOURCE entries;
|
|
each queue name is prefixed by \\Server\.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is (DWORD_PTR) -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes required to get the
|
|
first entry. This value is returned if WN_MORE_DATA is
|
|
the return code, and Buffer is too small to even fit one
|
|
entry.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
NO_ERROR is returned as long as at least one entry was written
|
|
into Buffer but does not necessarily mean that it's the number
|
|
of EntriesRequested.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - At least one entry was written to output buffer,
|
|
irregardless of the number requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit a single entry.
|
|
|
|
--*/ // NwEnumVolumesQueues
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
BOOL FitInBuffer = TRUE;
|
|
DWORD EntrySize;
|
|
|
|
CHAR VolumeName[NW_VOLUME_NAME_LEN]; // OEM volume name
|
|
LPWSTR UVolumeName = NULL; // Unicode volume name
|
|
DWORD NextObject = (DWORD) ContextHandle->ResumeId;
|
|
DWORD MaxVolumeNumber = ContextHandle->dwMaxVolumes;
|
|
ULONG Failures = 0;
|
|
|
|
//
|
|
// tommye - bug 139466
|
|
//
|
|
// removed if (NextObject >= 0) becaue NextObject is a DWORD
|
|
//
|
|
|
|
while (FitInBuffer &&
|
|
EntriesRequested > *EntriesRead &&
|
|
ContextHandle->ConnectionType == CONNTYPE_DISK &&
|
|
(NextObject < MaxVolumeNumber) &&
|
|
status == NO_ERROR) {
|
|
|
|
|
|
RtlZeroMemory(VolumeName, sizeof(VolumeName));
|
|
|
|
//
|
|
// Call the scan bindery object NCP to scan for all file
|
|
// volume objects.
|
|
//
|
|
status = NwGetNextVolumeEntry(
|
|
ContextHandle->TreeConnectionHandle,
|
|
NextObject++,
|
|
VolumeName
|
|
);
|
|
|
|
if (status == NO_ERROR) {
|
|
|
|
if (VolumeName[0] == 0) {
|
|
|
|
//
|
|
// Got an empty volume name back for the next volume number
|
|
// which indicates there is no volume associated with the
|
|
// volume number but still got error success.
|
|
//
|
|
// Treat this as having reached the end of the enumeration
|
|
// if we have had three failures in a row. This will allow
|
|
// us to function when there are small holes in the drive
|
|
// list.
|
|
//
|
|
|
|
Failures++;
|
|
|
|
if ( Failures <= 3 ) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
NextObject = (DWORD) -1;
|
|
ContextHandle->ResumeId = (DWORD_PTR) -1;
|
|
ContextHandle->ConnectionType = CONNTYPE_PRINT;
|
|
|
|
}
|
|
|
|
} else if (NwConvertToUnicode(&UVolumeName, VolumeName)) {
|
|
|
|
//
|
|
// Pack volume name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
ContextHandle->ContainerName,
|
|
NULL,
|
|
UVolumeName,
|
|
RESOURCE_GLOBALNET,
|
|
RESOURCEDISPLAYTYPE_SHARE,
|
|
#ifdef NT1057
|
|
RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_CONTAINER,
|
|
#else
|
|
RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_NOLOCALDEVICE,
|
|
#endif
|
|
RESOURCETYPE_DISK,
|
|
NULL,
|
|
NULL,
|
|
&EntrySize
|
|
);
|
|
|
|
if (status == WN_MORE_DATA) {
|
|
|
|
//
|
|
// Could not write current entry into output buffer.
|
|
//
|
|
|
|
if (*EntriesRead) {
|
|
//
|
|
// Still return success because we got at least one.
|
|
//
|
|
status = NO_ERROR;
|
|
}
|
|
else {
|
|
*BytesNeeded = EntrySize;
|
|
}
|
|
|
|
FitInBuffer = FALSE;
|
|
}
|
|
else if (status == NO_ERROR) {
|
|
|
|
//
|
|
// Note that we've returned the current entry.
|
|
//
|
|
(*EntriesRead)++;
|
|
|
|
ContextHandle->ResumeId = NextObject;
|
|
}
|
|
|
|
(void) LocalFree((HLOCAL) UVolumeName);
|
|
}
|
|
|
|
//
|
|
// Reset the failures counter.
|
|
//
|
|
|
|
Failures = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// User asked for more than there are entries. We just say that
|
|
// all is well.
|
|
//
|
|
if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
|
|
{
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
if ( *EntriesRead == 0 &&
|
|
status == NO_ERROR &&
|
|
ContextHandle->ConnectionType == CONNTYPE_DISK )
|
|
{
|
|
ContextHandle->ConnectionType = CONNTYPE_PRINT;
|
|
ContextHandle->ResumeId = (DWORD_PTR) -1;
|
|
}
|
|
|
|
//
|
|
// The user needs to be validated on a netware311 server to
|
|
// get the print queues. So, we need to close the handle and
|
|
// open a new one with WRITE access. If any error occurred while
|
|
// we are enumerating the print queues, we will abort and
|
|
// assume there are no print queues on the server.
|
|
//
|
|
|
|
if ( FitInBuffer &&
|
|
EntriesRequested > *EntriesRead &&
|
|
ContextHandle->ConnectionType == CONNTYPE_PRINT &&
|
|
status == NO_ERROR )
|
|
{
|
|
UNICODE_STRING TreeConnectStr;
|
|
DWORD QueueEntriesRead = 0;
|
|
|
|
(void) NtClose(ContextHandle->TreeConnectionHandle);
|
|
|
|
//
|
|
// Open a tree connection handle to \Device\NwRdr\ContainerName
|
|
//
|
|
status = NwCreateTreeConnectName(
|
|
ContextHandle->ContainerName,
|
|
NULL,
|
|
&TreeConnectStr );
|
|
|
|
if (status != NO_ERROR)
|
|
return (*EntriesRead? NO_ERROR: WN_NO_MORE_ENTRIES );
|
|
|
|
|
|
status = NwOpenCreateConnection(
|
|
&TreeConnectStr,
|
|
NULL,
|
|
NULL,
|
|
ContextHandle->ContainerName,
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_WRITE_DATA,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
RESOURCETYPE_PRINT, // Only matters when connecting beyond servername
|
|
&ContextHandle->TreeConnectionHandle,
|
|
NULL );
|
|
|
|
(void) LocalFree((HLOCAL) TreeConnectStr.Buffer);
|
|
|
|
if (status != NO_ERROR)
|
|
return (*EntriesRead? NO_ERROR: WN_NO_MORE_ENTRIES );
|
|
|
|
status = NwEnumQueues(
|
|
ContextHandle,
|
|
EntriesRequested == (DWORD_PTR) -1?
|
|
EntriesRequested : (EntriesRequested - *EntriesRead),
|
|
FixedPortion,
|
|
(DWORD) ((LPBYTE) EndOfVariableData - (LPBYTE) FixedPortion),
|
|
BytesNeeded,
|
|
&QueueEntriesRead );
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
*EntriesRead += QueueEntriesRead;
|
|
}
|
|
else if ( *EntriesRead )
|
|
{
|
|
//
|
|
// As long as we read something into the buffer,
|
|
// we should return success.
|
|
//
|
|
status = NO_ERROR;
|
|
*BytesNeeded = 0;
|
|
}
|
|
|
|
}
|
|
|
|
if ( status == NO_ERROR &&
|
|
*EntriesRead == 0 &&
|
|
ContextHandle->ConnectionType == CONNTYPE_PRINT )
|
|
{
|
|
return WN_NO_MORE_ENTRIES;
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NwEnumQueues(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates all the queues on a server.
|
|
The queue entries are returned in an array of NETRESOURCE entries;
|
|
each queue name is prefixed by \\Server\.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is (DWORD_PTR) -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes required to get the
|
|
first entry. This value is returned iff WN_MORE_DATA is
|
|
the return code, and Buffer is too small to even fit one
|
|
entry.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
NO_ERROR is returned as long as at least one entry was written
|
|
into Buffer but does not necessarily mean that it's the number
|
|
of EntriesRequested.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - At least one entry was written to output buffer,
|
|
irregardless of the number requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit a single entry.
|
|
|
|
--*/ // NwEnumQueues
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
BOOL FitInBuffer = TRUE;
|
|
DWORD EntrySize;
|
|
|
|
DWORD NextObject = (DWORD) ContextHandle->ResumeId;
|
|
|
|
SERVERNAME QueueName; // OEM queue name
|
|
LPWSTR UQueueName = NULL; // Unicode queue name
|
|
|
|
while ( FitInBuffer &&
|
|
EntriesRequested > *EntriesRead &&
|
|
status == NO_ERROR ) {
|
|
|
|
RtlZeroMemory(QueueName, sizeof(QueueName));
|
|
|
|
//
|
|
// Call the scan bindery object NCP to scan for all file
|
|
// volume objects.
|
|
//
|
|
status = NwGetNextQueueEntry(
|
|
ContextHandle->TreeConnectionHandle,
|
|
&NextObject,
|
|
QueueName
|
|
);
|
|
|
|
if (status == NO_ERROR && NwConvertToUnicode(&UQueueName, QueueName)) {
|
|
|
|
//
|
|
// Pack server name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
ContextHandle->ContainerName,
|
|
NULL,
|
|
UQueueName,
|
|
RESOURCE_GLOBALNET,
|
|
RESOURCEDISPLAYTYPE_SHARE,
|
|
RESOURCEUSAGE_CONNECTABLE,
|
|
RESOURCETYPE_PRINT,
|
|
NULL,
|
|
NULL,
|
|
&EntrySize
|
|
);
|
|
|
|
if (status == WN_MORE_DATA) {
|
|
|
|
//
|
|
// Could not write current entry into output buffer.
|
|
//
|
|
|
|
if (*EntriesRead) {
|
|
//
|
|
// Still return success because we got at least one.
|
|
//
|
|
status = NO_ERROR;
|
|
}
|
|
else {
|
|
*BytesNeeded = EntrySize;
|
|
}
|
|
|
|
FitInBuffer = FALSE;
|
|
}
|
|
else if (status == NO_ERROR) {
|
|
|
|
//
|
|
// Note that we've returned the current entry.
|
|
//
|
|
(*EntriesRead)++;
|
|
|
|
ContextHandle->ResumeId = (DWORD_PTR) NextObject;
|
|
}
|
|
|
|
(void) LocalFree((HLOCAL) UQueueName);
|
|
}
|
|
}
|
|
|
|
if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwEnumDirectories(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates the directories of a given directory
|
|
handle by calling NtQueryDirectoryFile. It returns the
|
|
fully-qualified UNC path of the directory entries in an array
|
|
of NETRESOURCE entries.
|
|
|
|
The ContextHandle->ResumeId field is 0 initially, and contains
|
|
a pointer to the directory name string of the last directory
|
|
returned. If there are no more directories to return, this
|
|
field is set to (DWORD_PTR) -1.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle. It contains
|
|
an opened directory handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is (DWORD_PTR) -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes required to get the
|
|
first entry. This value is returned iff WN_MORE_DATA is
|
|
the return code, and Buffer is too small to even fit one
|
|
entry.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
NO_ERROR is returned as long as at least one entry was written
|
|
into Buffer but does not necessarily mean that it's the number
|
|
of EntriesRequested.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - At least one entry was written to output buffer,
|
|
irregardless of the number requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit a single entry.
|
|
|
|
--*/ // NwEnumDirectories
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
BOOL FitInBuffer = TRUE;
|
|
DWORD EntrySize;
|
|
|
|
if (ContextHandle->ResumeId == (DWORD_PTR) -1) {
|
|
//
|
|
// Reached the end of enumeration.
|
|
//
|
|
return WN_NO_MORE_ENTRIES;
|
|
}
|
|
|
|
while (FitInBuffer &&
|
|
EntriesRequested > *EntriesRead &&
|
|
status == NO_ERROR) {
|
|
|
|
if (ContextHandle->ResumeId == 0) {
|
|
|
|
//
|
|
// Get the first directory entry.
|
|
//
|
|
status = NwGetFirstDirectoryEntry(
|
|
ContextHandle->TreeConnectionHandle,
|
|
(LPWSTR *) &ContextHandle->ResumeId
|
|
);
|
|
}
|
|
|
|
//
|
|
// Either ResumeId contains the first entry we just got from
|
|
// NwGetFirstDirectoryEntry or it contains the next directory
|
|
// entry to return.
|
|
//
|
|
if (ContextHandle->ResumeId != 0) {
|
|
|
|
//
|
|
// Pack directory name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
ContextHandle->ContainerName,
|
|
NULL,
|
|
(LPWSTR) ContextHandle->ResumeId,
|
|
RESOURCE_GLOBALNET,
|
|
RESOURCEDISPLAYTYPE_SHARE,
|
|
#ifdef NT1057
|
|
RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_CONTAINER,
|
|
#else
|
|
RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_NOLOCALDEVICE,
|
|
#endif
|
|
RESOURCETYPE_DISK,
|
|
NULL,
|
|
NULL,
|
|
&EntrySize
|
|
);
|
|
|
|
if (status == WN_MORE_DATA) {
|
|
|
|
//
|
|
// Could not write current entry into output buffer.
|
|
//
|
|
|
|
if (*EntriesRead) {
|
|
//
|
|
// Still return success because we got at least one.
|
|
//
|
|
status = NO_ERROR;
|
|
}
|
|
else {
|
|
*BytesNeeded = EntrySize;
|
|
}
|
|
|
|
FitInBuffer = FALSE;
|
|
}
|
|
else if (status == NO_ERROR) {
|
|
|
|
//
|
|
// Note that we've returned the current entry.
|
|
//
|
|
(*EntriesRead)++;
|
|
|
|
//
|
|
// Free memory allocated to save resume point, which is
|
|
// a buffer that contains the last directory we returned.
|
|
//
|
|
if (ContextHandle->ResumeId != 0) {
|
|
(void) LocalFree((HLOCAL) ContextHandle->ResumeId);
|
|
ContextHandle->ResumeId = 0;
|
|
}
|
|
|
|
//
|
|
// Get next directory entry.
|
|
//
|
|
status = NwGetNextDirectoryEntry(
|
|
(LPWSTR) ContextHandle->TreeConnectionHandle,
|
|
(LPWSTR *) &ContextHandle->ResumeId
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
if (status == WN_NO_MORE_ENTRIES) {
|
|
ContextHandle->ResumeId = (DWORD_PTR) -1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// User asked for more than there are entries. We just say that
|
|
// all is well.
|
|
//
|
|
// This is incompliance with the wierd provider API definition where
|
|
// if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
|
|
// at least one entry fit into output buffer, there's no telling if
|
|
// the buffer was too small for more entries or there are no more
|
|
// entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
|
|
// before knowing that the last call had actually reached the end of list.
|
|
//
|
|
if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("EnumDirectories returns %lu\n", status));
|
|
}
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwEnumPrintServers(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates all the servers and NDS tree on the local network
|
|
by scanning the bindery for file server or directory objects on the
|
|
preferred server. The server and tree entries are returned in an
|
|
array of PRINTER_INFO_1 entries; each entry name is prefixed by
|
|
\\.
|
|
|
|
The ContextHandle->ResumeId field is initially (DWORD_PTR) -1 before
|
|
enumeration begins and contains the object ID of the last server
|
|
object returned.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is (DWORD_PTR) -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes copied or required to get all
|
|
the requested entries.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - Buffer contains all the entries requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit the requested entries.
|
|
|
|
--*/ // NwEnumPrintServers
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
DWORD EntrySize;
|
|
BOOL FitInBuffer = TRUE;
|
|
|
|
SERVERNAME ServerName; // OEM server name
|
|
LPWSTR UServerName = NULL; // Unicode server name
|
|
DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
|
|
WCHAR TempBuffer[500];
|
|
|
|
while ( EntriesRequested > *EntriesRead &&
|
|
ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NDS &&
|
|
((status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER)))
|
|
{
|
|
//
|
|
// Call the scan bindery object NCP to scan for all NDS
|
|
// tree objects.
|
|
//
|
|
status = NwGetNextNdsTreeEntry( ContextHandle );
|
|
|
|
if ( status == NO_ERROR && ContextHandle->ResumeId != 0 )
|
|
{
|
|
//
|
|
// Put tree name into a buffer
|
|
//
|
|
RtlZeroMemory( TempBuffer, 500 );
|
|
wcscat( TempBuffer, (LPWSTR) ContextHandle->ResumeId );
|
|
|
|
//
|
|
// Pack server name into output buffer.
|
|
//
|
|
status = NwWritePrinterInfoEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
NULL,
|
|
TempBuffer, // This is a NDS tree name
|
|
PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON1,
|
|
&EntrySize
|
|
);
|
|
|
|
switch ( status )
|
|
{
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
FitInBuffer = FALSE;
|
|
// Falls through
|
|
|
|
case NO_ERROR:
|
|
*BytesNeeded += EntrySize;
|
|
(*EntriesRead)++;
|
|
// ContextHandle->ResumeId = LastObjectId;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if ( status == WN_NO_MORE_ENTRIES )
|
|
{
|
|
//
|
|
// We processed the last item in list, so
|
|
// start enumerating servers.
|
|
//
|
|
ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
|
|
ContextHandle->ResumeId = (DWORD_PTR) -1;
|
|
LastObjectId = (DWORD) -1;
|
|
}
|
|
}
|
|
|
|
status = NO_ERROR;
|
|
|
|
while ( EntriesRequested > *EntriesRead &&
|
|
ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NON_NDS &&
|
|
((status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER))) {
|
|
|
|
RtlZeroMemory(ServerName, sizeof(ServerName));
|
|
|
|
//
|
|
// Call the scan bindery object NCP to scan for all file
|
|
// server objects.
|
|
//
|
|
status = NwGetNextServerEntry(
|
|
ContextHandle->TreeConnectionHandle,
|
|
&LastObjectId,
|
|
ServerName
|
|
);
|
|
|
|
if (status == NO_ERROR && NwConvertToUnicode(&UServerName,ServerName)) {
|
|
|
|
//
|
|
// Pack server name into output buffer.
|
|
//
|
|
status = NwWritePrinterInfoEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
NULL,
|
|
UServerName,
|
|
PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON3,
|
|
&EntrySize
|
|
);
|
|
|
|
switch ( status )
|
|
{
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
FitInBuffer = FALSE;
|
|
// Falls through
|
|
|
|
case NO_ERROR:
|
|
*BytesNeeded += EntrySize;
|
|
(*EntriesRead)++;
|
|
ContextHandle->ResumeId = (DWORD_PTR) LastObjectId;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
(void) LocalFree((HLOCAL) UServerName);
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is incompliance with the wierd provider API definition where
|
|
// if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
|
|
// at least one entry fit into output buffer, there's no telling if
|
|
// the buffer was too small for more entries or there are no more
|
|
//
|
|
// This is incompliance with the wierd provider API definition where
|
|
// if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
|
|
// at least one entry fit into output buffer, there's no telling if
|
|
// the buffer was too small for more entries or there are no more
|
|
// entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
|
|
// before knowing that the last call had actually reached the end of list.
|
|
//
|
|
if ( !FitInBuffer ) {
|
|
*EntriesRead = 0;
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwEnumPrintQueues(
|
|
IN LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD_PTR EntriesRequested,
|
|
OUT LPBYTE Buffer,
|
|
IN DWORD BufferSize,
|
|
OUT LPDWORD BytesNeeded,
|
|
OUT LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enumerates all the print queues on a server by scanning
|
|
the bindery on the server for print queues objects.
|
|
The print queues entries are returned in an array of PRINTER_INFO_1 entries
|
|
and each printer name is prefixed by \\Server\.
|
|
|
|
The ContextHandle->ResumeId field is initially (DWORD_PTR) -1 before
|
|
enumeration begins and contains the object ID of the last print queue
|
|
object returned.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Supplies the enum context handle.
|
|
|
|
EntriesRequested - Supplies the number of entries to return. If
|
|
this value is (DWORD_PTR) -1, return all available entries.
|
|
|
|
Buffer - Receives the entries we are listing.
|
|
|
|
BufferSize - Supplies the size of the output buffer.
|
|
|
|
BytesNeeded - Receives the number of bytes copied or required to get all
|
|
the requested entries.
|
|
|
|
EntriesRead - Receives the number of entries returned in Buffer.
|
|
This value is only returned iff NO_ERROR is the return code.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - Buffer contains all the entries requested.
|
|
|
|
WN_NO_MORE_ENTRIES - No entries left to return.
|
|
|
|
WN_MORE_DATA - The buffer was too small to fit the requested entries.
|
|
|
|
--*/ // NwEnumPrintQueues
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
|
|
LPBYTE FixedPortion = Buffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
|
|
|
|
DWORD EntrySize;
|
|
BOOL FitInBuffer = TRUE;
|
|
|
|
SERVERNAME QueueName; // OEM queue name
|
|
LPWSTR UQueueName = NULL; // Unicode queue name
|
|
DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
|
|
|
|
while ( EntriesRequested > *EntriesRead &&
|
|
( (status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER))) {
|
|
|
|
RtlZeroMemory(QueueName, sizeof(QueueName));
|
|
|
|
//
|
|
// Call the scan bindery object NCP to scan for all file
|
|
// volume objects.
|
|
//
|
|
status = NwGetNextQueueEntry(
|
|
ContextHandle->TreeConnectionHandle,
|
|
&LastObjectId,
|
|
QueueName
|
|
);
|
|
|
|
if (status == NO_ERROR && NwConvertToUnicode(&UQueueName, QueueName)) {
|
|
|
|
//
|
|
// Pack server name into output buffer.
|
|
//
|
|
status = NwWritePrinterInfoEntry(
|
|
&FixedPortion,
|
|
&EndOfVariableData,
|
|
ContextHandle->ContainerName,
|
|
UQueueName,
|
|
PRINTER_ENUM_ICON8,
|
|
&EntrySize
|
|
);
|
|
|
|
switch ( status )
|
|
{
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
FitInBuffer = FALSE;
|
|
// Falls through
|
|
|
|
case NO_ERROR:
|
|
*BytesNeeded += EntrySize;
|
|
(*EntriesRead)++;
|
|
ContextHandle->ResumeId = (DWORD_PTR) LastObjectId;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
(void) LocalFree((HLOCAL) UQueueName);
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is incompliance with the wierd provider API definition where
|
|
// if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
|
|
// at least one entry fit into output buffer, there's no telling if
|
|
// the buffer was too small for more entries or there are no more
|
|
// entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
|
|
// before knowing that the last call had actually reached the end of list.
|
|
//
|
|
if ( !FitInBuffer ) {
|
|
*EntriesRead = 0;
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrCloseEnum(
|
|
IN OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function closes an enum context handle.
|
|
|
|
Arguments:
|
|
|
|
EnumHandle - Supplies a pointer to the enum context handle.
|
|
|
|
Return Value:
|
|
|
|
WN_BAD_HANDLE - Handle is not recognizable.
|
|
|
|
NO_ERROR - Call was successful.
|
|
|
|
--*/ // NwrCloseEnum
|
|
{
|
|
|
|
LPNW_ENUM_CONTEXT ContextHandle = (LPNW_ENUM_CONTEXT) *EnumHandle;
|
|
DWORD status = NO_ERROR ;
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM)
|
|
{
|
|
KdPrint(("\nNWWORKSTATION: NwrCloseEnum\n"));
|
|
}
|
|
#endif
|
|
|
|
if (ContextHandle->Signature != NW_HANDLE_SIGNATURE)
|
|
{
|
|
ASSERT(FALSE);
|
|
return WN_BAD_HANDLE;
|
|
}
|
|
|
|
//
|
|
// Resume handle for listing directories is a buffer which contains
|
|
// the last directory returned.
|
|
//
|
|
if (ContextHandle->HandleType == NwsHandleListDirectories &&
|
|
ContextHandle->ResumeId != 0 &&
|
|
ContextHandle->ResumeId != (DWORD_PTR) -1)
|
|
{
|
|
(void) LocalFree((HLOCAL) ContextHandle->ResumeId);
|
|
}
|
|
|
|
//
|
|
// NdsRawDataBuffer handle for listing NDS tree subordinates is a buffer which contains
|
|
// the last data chunk returned from redirector.
|
|
//
|
|
if ( ( ContextHandle->HandleType == NwsHandleListNdsSubTrees_Disk ||
|
|
ContextHandle->HandleType == NwsHandleListNdsSubTrees_Print ||
|
|
ContextHandle->HandleType == NwsHandleListNdsSubTrees_Any ||
|
|
ContextHandle->HandleType == NwsHandleListServersAndNdsTrees ) &&
|
|
ContextHandle->NdsRawDataBuffer )
|
|
{
|
|
(void) LocalFree((HLOCAL) ContextHandle->NdsRawDataBuffer);
|
|
ContextHandle->NdsRawDataBuffer = 0;
|
|
}
|
|
|
|
if (ContextHandle->TreeConnectionHandle != (HANDLE) NULL)
|
|
{
|
|
if (ContextHandle->HandleType == NwsHandleListDirectories)
|
|
{
|
|
//
|
|
// Delete the UNC connection created so that we can browse
|
|
// directories.
|
|
//
|
|
(void) NwNukeConnection(ContextHandle->TreeConnectionHandle, TRUE);
|
|
}
|
|
|
|
if ( ContextHandle->HandleType == NwsHandleListNdsSubTrees_Disk ||
|
|
ContextHandle->HandleType == NwsHandleListNdsSubTrees_Print ||
|
|
ContextHandle->HandleType == NwsHandleListNdsSubTrees_Any )
|
|
{
|
|
//
|
|
// Get rid of the connection to the NDS tree.
|
|
//
|
|
(void) CloseHandle(ContextHandle->TreeConnectionHandle);
|
|
ContextHandle->TreeConnectionHandle = 0;
|
|
}
|
|
else
|
|
{
|
|
(void) NtClose(ContextHandle->TreeConnectionHandle);
|
|
ContextHandle->TreeConnectionHandle = 0;
|
|
}
|
|
}
|
|
|
|
ContextHandle->Signature = 0x0BADBAD0;
|
|
(void) LocalFree((HLOCAL) ContextHandle);
|
|
|
|
*EnumHandle = NULL;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrGetUser(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN LPWSTR lpName,
|
|
OUT LPBYTE lpUserName,
|
|
IN DWORD dwUserNameBufferSize,
|
|
OUT LPDWORD lpdwCharsRequired
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is used to determine either the current default username, or the
|
|
username used to establish a network connection.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
|
|
lpName - The connection for which user information is requested.
|
|
|
|
lpUserName - The buffer to receive the user name associated with the
|
|
connection referred to by lpName.
|
|
|
|
dwUserNameLen - The size of the buffer lpUserName.
|
|
|
|
lpdwCharsRequired - If return status is WN_MORE_DATA, then this is set to
|
|
the value which indicates the number of characters that the buffer
|
|
lpUserName must hold. Otherwise, this is not set.
|
|
|
|
|
|
Return Value:
|
|
|
|
WN_SUCCESS - If the call is successful. Otherwise, an error code is,
|
|
returned, which may include:
|
|
|
|
WN_NOT_CONNECTED - lpName not a redirected device nor a connected network
|
|
name.
|
|
|
|
WN_MORE_DATA - The buffer is too small.
|
|
|
|
--*/ // NwrGetUser
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
WCHAR lpTempUserName[512];
|
|
WCHAR lpTempHostName[512];
|
|
|
|
if (lpName == NULL)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
status = NwGetConnectionInformation( lpName, lpTempUserName, lpTempHostName );
|
|
|
|
if ( status == ERROR_BAD_NETPATH )
|
|
{
|
|
return WN_NOT_CONNECTED;
|
|
}
|
|
if ( status != NO_ERROR )
|
|
{
|
|
return status;
|
|
}
|
|
|
|
if ( ( ( wcslen( lpTempUserName ) + 1 ) * sizeof(WCHAR) ) > dwUserNameBufferSize )
|
|
{
|
|
*lpdwCharsRequired = wcslen( lpTempUserName ) + 1;
|
|
return WN_MORE_DATA;
|
|
}
|
|
|
|
wcscpy( (LPWSTR) lpUserName, lpTempUserName );
|
|
|
|
return WN_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrGetResourceInformation(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN LPWSTR lpRemoteName,
|
|
IN DWORD dwType,
|
|
OUT LPBYTE lpBuffer,
|
|
IN DWORD dwBufferSize,
|
|
OUT LPDWORD lpdwBytesNeeded,
|
|
OUT LPDWORD lpdwSystemOffset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns an object which details information
|
|
about a specified network resource.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
lpRemoteName - The full path name to be verified.
|
|
dwType - The type of the value, if the calling client knows it.
|
|
lpBuffer - A pointer to a buffer to receive a single NETRESOURCE entry.
|
|
dwBufferSize - The size of the buffer.
|
|
lpdwBytesNeeded - The buffer size needed if WN_MORE_DATA is returned.
|
|
lpdwSystemOffset - A DWORD that is an offset value to the beginning of a
|
|
string that specifies the part of the resource that is accessed through
|
|
resource type specific APIs rather than WNet APIs. The string is stored
|
|
in the same buffer as the returned NETRESOURCE structure, lpBuffer.
|
|
|
|
Return Value:
|
|
|
|
WN_SUCCESS - If the call is successful.
|
|
|
|
WN_MORE_DATA - If input buffer is too small.
|
|
|
|
WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
|
|
of parameters is specified (e.g. lpRemoteName does not correspond
|
|
to dwType).
|
|
|
|
WN_BAD_NETNAME - The resource is not recognized by this provider.
|
|
|
|
--*/ // NwrGetResourceInformation
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
DWORD EntrySize;
|
|
|
|
LPBYTE FixedPortion = lpBuffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(dwBufferSize,ALIGN_DWORD));
|
|
LPWSTR lpObjectPathName = NULL;
|
|
LPWSTR lpSystemPathPart = NULL;
|
|
LPWSTR lpSystem = NULL;
|
|
DWORD ClassType;
|
|
DWORD ResourceScope = RESOURCE_CONTEXT; // prefix issue
|
|
DWORD ResourceType = 0;
|
|
DWORD ResourceDisplayType;
|
|
DWORD ResourceUsage;
|
|
BOOL fReturnBadNetName = FALSE;
|
|
|
|
if (lpRemoteName == NULL)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*lpdwSystemOffset = 0;
|
|
|
|
status = NwGetNDSPathInfo( lpRemoteName,
|
|
&lpObjectPathName,
|
|
&lpSystemPathPart,
|
|
&ClassType,
|
|
&ResourceScope,
|
|
&ResourceType,
|
|
&ResourceDisplayType,
|
|
&ResourceUsage );
|
|
|
|
if ( status == VERIFY_ERROR_NOT_A_NDS_TREE )
|
|
{
|
|
//
|
|
// Code to handle \\SERVER\VOL\... here!
|
|
//
|
|
status = NwGetBinderyPathInfo( lpRemoteName,
|
|
&lpObjectPathName,
|
|
&lpSystemPathPart,
|
|
&ClassType,
|
|
&ResourceScope,
|
|
&ResourceType,
|
|
&ResourceDisplayType,
|
|
&ResourceUsage );
|
|
}
|
|
|
|
if ( status == VERIFY_ERROR_PATH_NOT_FOUND )
|
|
{
|
|
fReturnBadNetName = TRUE;
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
if ( status == NO_ERROR &&
|
|
dwType != RESOURCETYPE_ANY &&
|
|
ResourceType != RESOURCETYPE_ANY &&
|
|
dwType != ResourceType )
|
|
{
|
|
status = WN_BAD_VALUE;
|
|
}
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
//
|
|
// Pack subtree name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry( &FixedPortion,
|
|
&EndOfVariableData,
|
|
NULL,
|
|
NULL,
|
|
lpObjectPathName == NULL ? NwProviderName : lpObjectPathName,
|
|
ResourceScope,
|
|
ResourceDisplayType,
|
|
ResourceUsage,
|
|
ResourceType,
|
|
lpSystemPathPart,
|
|
&lpSystem,
|
|
&EntrySize );
|
|
|
|
if ( lpObjectPathName )
|
|
(void) LocalFree( (HLOCAL) lpObjectPathName );
|
|
}
|
|
else
|
|
{
|
|
if ( lpSystemPathPart != NULL )
|
|
{
|
|
(void) LocalFree( (HLOCAL) lpSystemPathPart );
|
|
lpSystemPathPart = NULL;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
if (status == WN_MORE_DATA)
|
|
{
|
|
//
|
|
// Could not write current entry into output buffer.
|
|
//
|
|
*lpdwBytesNeeded = EntrySize;
|
|
}
|
|
|
|
if ( lpSystemPathPart != NULL )
|
|
{
|
|
(void) LocalFree( (HLOCAL) lpSystemPathPart );
|
|
lpSystemPathPart = NULL;
|
|
}
|
|
|
|
if ( fReturnBadNetName )
|
|
return WN_BAD_NETNAME;
|
|
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
LPNETRESOURCEW NetR = (LPNETRESOURCEW) lpBuffer;
|
|
|
|
//
|
|
// Replace pointers to strings with offsets as need
|
|
//
|
|
|
|
if (NetR->lpLocalName != NULL)
|
|
{
|
|
NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) lpBuffer);
|
|
}
|
|
|
|
NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR) lpBuffer);
|
|
|
|
if (NetR->lpComment != NULL)
|
|
{
|
|
NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) - (DWORD_PTR) lpBuffer);
|
|
}
|
|
|
|
if (NetR->lpProvider != NULL)
|
|
{
|
|
NetR->lpProvider = (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) - (DWORD_PTR) lpBuffer);
|
|
}
|
|
|
|
if (lpSystem != NULL)
|
|
{
|
|
*lpdwSystemOffset = (DWORD)((DWORD_PTR) lpSystem - (DWORD_PTR) lpBuffer);
|
|
}
|
|
|
|
if ( lpSystemPathPart != NULL )
|
|
{
|
|
(void) LocalFree( (HLOCAL) lpSystemPathPart );
|
|
lpSystemPathPart = NULL;
|
|
}
|
|
|
|
if ( fReturnBadNetName )
|
|
return WN_BAD_NETNAME;
|
|
|
|
return WN_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrGetResourceParent(
|
|
IN LPWSTR Reserved OPTIONAL,
|
|
IN LPWSTR lpRemoteName,
|
|
IN DWORD dwType,
|
|
OUT LPBYTE lpBuffer,
|
|
IN DWORD dwBufferSize,
|
|
OUT LPDWORD lpdwBytesNeeded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns an object which details information
|
|
about the parent of a specified network resource.
|
|
|
|
Arguments:
|
|
|
|
Reserved - Unused.
|
|
lpRemoteName - The full path name of object to find the parent of.
|
|
dwType - The type of the value, if the calling client knows it.
|
|
lpBuffer - A pointer to a buffer to receive a single NETRESOURCE entry.
|
|
dwBufferSize - The size of the buffer.
|
|
lpdwBytesNeeded - The buffer size needed if WN_MORE_DATA is returned.
|
|
|
|
Return Value:
|
|
|
|
WN_SUCCESS - If the call is successful.
|
|
|
|
WN_MORE_DATA - If input buffer is too small.
|
|
|
|
WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
|
|
of parameters is specified (e.g. lpRemoteName does not correspond
|
|
to dwType).
|
|
|
|
--*/ // NwrGetResourceParent
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
DWORD EntrySize;
|
|
|
|
LPBYTE FixedPortion = lpBuffer;
|
|
LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
|
|
ROUND_DOWN_COUNT(dwBufferSize,ALIGN_DWORD));
|
|
LPWSTR lpRemoteNameParent = NULL;
|
|
LPWSTR lpFullObjectPathName = NULL;
|
|
DWORD ClassType;
|
|
DWORD ResourceScope;
|
|
DWORD ResourceType;
|
|
DWORD ResourceDisplayType;
|
|
DWORD ResourceUsage;
|
|
BOOL fReturnBadNetName = FALSE;
|
|
|
|
if (lpRemoteName == NULL)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( ! NwGetRemoteNameParent( lpRemoteName, &lpRemoteNameParent ) )
|
|
{
|
|
return WN_BAD_NETNAME;
|
|
}
|
|
|
|
status = NwVerifyNDSObject( lpRemoteNameParent,
|
|
&lpFullObjectPathName,
|
|
&ClassType,
|
|
&ResourceScope,
|
|
&ResourceType,
|
|
&ResourceDisplayType,
|
|
&ResourceUsage );
|
|
|
|
if ( status == VERIFY_ERROR_NOT_A_NDS_TREE )
|
|
{
|
|
status = NwVerifyBinderyObject( lpRemoteNameParent,
|
|
&lpFullObjectPathName,
|
|
&ClassType,
|
|
&ResourceScope,
|
|
&ResourceType,
|
|
&ResourceDisplayType,
|
|
&ResourceUsage );
|
|
}
|
|
|
|
if ( lpRemoteNameParent )
|
|
(void) LocalFree( (HLOCAL) lpRemoteNameParent );
|
|
|
|
if ( status == VERIFY_ERROR_PATH_NOT_FOUND )
|
|
{
|
|
fReturnBadNetName = TRUE;
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
//
|
|
// Pack subtree name into output buffer.
|
|
//
|
|
status = NwWriteNetResourceEntry( &FixedPortion,
|
|
&EndOfVariableData,
|
|
NULL,
|
|
NULL,
|
|
lpFullObjectPathName == NULL ? NwProviderName : lpFullObjectPathName,
|
|
ResourceScope,
|
|
ResourceDisplayType,
|
|
ResourceUsage,
|
|
ResourceType,
|
|
NULL,
|
|
NULL,
|
|
&EntrySize );
|
|
|
|
if ( lpFullObjectPathName )
|
|
(void) LocalFree( (HLOCAL) lpFullObjectPathName );
|
|
}
|
|
else
|
|
{
|
|
return status;
|
|
}
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
if (status == WN_MORE_DATA)
|
|
{
|
|
//
|
|
// Could not write current entry into output buffer.
|
|
//
|
|
*lpdwBytesNeeded = EntrySize;
|
|
}
|
|
|
|
if ( fReturnBadNetName )
|
|
return WN_BAD_NETNAME;
|
|
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
LPNETRESOURCEW NetR = (LPNETRESOURCEW) lpBuffer;
|
|
|
|
//
|
|
// Replace pointers to strings with offsets as need
|
|
//
|
|
|
|
if (NetR->lpLocalName != NULL)
|
|
{
|
|
NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) lpBuffer);
|
|
}
|
|
|
|
NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR) lpBuffer);
|
|
|
|
if (NetR->lpComment != NULL)
|
|
{
|
|
NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) - (DWORD_PTR) lpBuffer);
|
|
}
|
|
|
|
if (NetR->lpProvider != NULL)
|
|
{
|
|
NetR->lpProvider = (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) - (DWORD_PTR) lpBuffer);
|
|
}
|
|
|
|
if ( fReturnBadNetName )
|
|
return WN_BAD_NETNAME;
|
|
|
|
return WN_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
NWWKSTA_CONTEXT_HANDLE_rundown(
|
|
IN NWWKSTA_CONTEXT_HANDLE EnumHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by RPC when a client terminates with an
|
|
opened handle. This allows us to clean up and deallocate any context
|
|
data associated with the handle.
|
|
|
|
Arguments:
|
|
|
|
EnumHandle - Supplies the handle opened for an enumeration.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Call our close handle routine.
|
|
//
|
|
NwrCloseEnum(&EnumHandle);
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwGetFirstNdsSubTreeEntry(
|
|
OUT LPNW_ENUM_CONTEXT ContextHandle,
|
|
IN DWORD BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by NwEnumNdsSubTrees to get the first
|
|
subtree entry given a handle to a NDS tree. It allocates
|
|
the output buffer to hold the returned subtree name; the
|
|
caller should free this output buffer with LocalFree when done.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - The operation was successful.
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
|
|
buffer.
|
|
|
|
Other errors from NwNdsList.
|
|
|
|
--*/ // NwGetFirstNdsSubTreeEntry
|
|
{
|
|
NTSTATUS ntstatus;
|
|
|
|
ContextHandle->NdsRawDataSize = BufferSize;
|
|
|
|
//
|
|
// Determine size of NDS raw data buffer to use.
|
|
//
|
|
if ( ContextHandle->NdsRawDataSize < EIGHT_KB )
|
|
ContextHandle->NdsRawDataSize = EIGHT_KB;
|
|
|
|
else // dfergus 19 Apr 2001 - 346859
|
|
// if buffer too big, set to max NDS buffer size
|
|
if (ContextHandle->NdsRawDataSize > 0xFC00) // NW_MAX_BUFFER = 0xFC00
|
|
ContextHandle->NdsRawDataSize = 0xFC00;
|
|
|
|
|
|
//
|
|
// Create NDS raw data buffer.
|
|
//
|
|
ContextHandle->NdsRawDataBuffer = (DWORD_PTR)
|
|
LocalAlloc( LMEM_ZEROINIT,
|
|
ContextHandle->NdsRawDataSize );
|
|
|
|
if ( ContextHandle->NdsRawDataBuffer == 0 )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwGetFirstNdsSubTreeEntry LocalAlloc Failed %lu\n", GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Set up to get initial NDS subordinate list.
|
|
//
|
|
ContextHandle->NdsRawDataId = INITIAL_ITERATION;
|
|
|
|
ntstatus = NwNdsList( ContextHandle->TreeConnectionHandle,
|
|
ContextHandle->dwOid,
|
|
&ContextHandle->NdsRawDataId,
|
|
(LPBYTE) ContextHandle->NdsRawDataBuffer,
|
|
ContextHandle->NdsRawDataSize );
|
|
|
|
//
|
|
// If error, clean up the ContextHandle and return.
|
|
//
|
|
if ( ntstatus != STATUS_SUCCESS ||
|
|
((PNDS_RESPONSE_SUBORDINATE_LIST)
|
|
ContextHandle->NdsRawDataBuffer)->SubordinateEntries == 0 )
|
|
{
|
|
if ( ContextHandle->NdsRawDataBuffer )
|
|
(void) LocalFree( (HLOCAL) ContextHandle->NdsRawDataBuffer );
|
|
ContextHandle->NdsRawDataBuffer = 0;
|
|
ContextHandle->NdsRawDataSize = 0;
|
|
ContextHandle->NdsRawDataId = INITIAL_ITERATION;
|
|
ContextHandle->NdsRawDataCount = 0;
|
|
ContextHandle->ResumeId = 0;
|
|
|
|
return WN_NO_MORE_ENTRIES;
|
|
}
|
|
|
|
ContextHandle->NdsRawDataCount = ((PNDS_RESPONSE_SUBORDINATE_LIST)
|
|
ContextHandle->NdsRawDataBuffer)->SubordinateEntries - 1;
|
|
|
|
ContextHandle->ResumeId = ContextHandle->NdsRawDataBuffer +
|
|
sizeof( NDS_RESPONSE_SUBORDINATE_LIST );
|
|
|
|
// Multi-user code merge
|
|
// 12/05/96 cjc Fix problem with FileManager not showing all the NDS entries.
|
|
// Problem occurs when the NDS entries don't fit in 1 NCP packet;
|
|
// need to keep track of the Iteration # and redo NCP.
|
|
|
|
ContextHandle->NdsRawDataId = ((PNDS_RESPONSE_SUBORDINATE_LIST)
|
|
ContextHandle->NdsRawDataBuffer)->IterationHandle;
|
|
|
|
return RtlNtStatusToDosError(ntstatus);
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwGetNextNdsSubTreeEntry(
|
|
OUT LPNW_ENUM_CONTEXT ContextHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by NwEnumNdsSubTrees to get the next
|
|
NDS subtree entry given a handle to a NDS tree. It allocates
|
|
the output buffer to hold the returned subtree name; the
|
|
caller should free this output buffer with LocalFree when done.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - The operation was successful.
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
|
|
buffer.
|
|
|
|
Other errors from NwNdsList.
|
|
|
|
--*/ // NwGetNextDirectoryEntry
|
|
{
|
|
NTSTATUS ntstatus = STATUS_SUCCESS;
|
|
PBYTE pbRaw;
|
|
DWORD dwStrLen;
|
|
|
|
|
|
if ( ContextHandle->NdsRawDataCount == 0 &&
|
|
ContextHandle->NdsRawDataId == INITIAL_ITERATION )
|
|
return WN_NO_MORE_ENTRIES;
|
|
|
|
if ( ContextHandle->NdsRawDataCount == 0 &&
|
|
ContextHandle->NdsRawDataId != INITIAL_ITERATION )
|
|
{
|
|
ntstatus = NwNdsList( ContextHandle->TreeConnectionHandle,
|
|
ContextHandle->dwOid,
|
|
&ContextHandle->NdsRawDataId,
|
|
(LPBYTE) ContextHandle->NdsRawDataBuffer,
|
|
ContextHandle->NdsRawDataSize );
|
|
|
|
//
|
|
// If error, clean up the ContextHandle and return.
|
|
//
|
|
if (ntstatus != STATUS_SUCCESS)
|
|
{
|
|
if ( ContextHandle->NdsRawDataBuffer )
|
|
(void) LocalFree( (HLOCAL) ContextHandle->NdsRawDataBuffer );
|
|
ContextHandle->NdsRawDataBuffer = 0;
|
|
ContextHandle->NdsRawDataSize = 0;
|
|
ContextHandle->NdsRawDataId = INITIAL_ITERATION;
|
|
ContextHandle->NdsRawDataCount = 0;
|
|
|
|
return WN_NO_MORE_ENTRIES;
|
|
}
|
|
|
|
ContextHandle->NdsRawDataCount = ((PNDS_RESPONSE_SUBORDINATE_LIST)
|
|
ContextHandle->NdsRawDataBuffer)->SubordinateEntries - 1;
|
|
|
|
ContextHandle->ResumeId = ContextHandle->NdsRawDataBuffer +
|
|
sizeof( NDS_RESPONSE_SUBORDINATE_LIST );
|
|
|
|
// ---Multi-user change ---
|
|
// 12/05/96 cjc Fix problem with FileManager not showing all the NDS entries.
|
|
// Problem occurs when the NDS entries don't fit in 1 NCP packet;
|
|
// need to keep track of the Iteration # and redo NCP.
|
|
|
|
ContextHandle->NdsRawDataId = ((PNDS_RESPONSE_SUBORDINATE_LIST)
|
|
ContextHandle->NdsRawDataBuffer)->IterationHandle;
|
|
return RtlNtStatusToDosError(ntstatus);
|
|
}
|
|
|
|
ContextHandle->NdsRawDataCount--;
|
|
|
|
//
|
|
// Move pointer past the fixed header portion of a NDS_RESPONSE_SUBORDINATE_ENTRY
|
|
//
|
|
pbRaw = (BYTE *) ContextHandle->ResumeId;
|
|
pbRaw += sizeof( NDS_RESPONSE_SUBORDINATE_ENTRY );
|
|
|
|
//
|
|
// Move pointer past the length value of the Class Name string
|
|
// of a NDS_RESPONSE_SUBORDINATE_ENTRY
|
|
//
|
|
dwStrLen = * (DWORD *) pbRaw;
|
|
pbRaw += sizeof( DWORD );
|
|
|
|
//
|
|
// Move pointer past the Class Name string of a NDS_RESPONSE_SUBORDINATE_ENTRY
|
|
//
|
|
pbRaw += ROUNDUP4( dwStrLen );
|
|
|
|
//
|
|
// Move pointer past the length value of the Object Name string
|
|
// of a NDS_RESPONSE_SUBORDINATE_ENTRY
|
|
//
|
|
dwStrLen = * (DWORD *) pbRaw;
|
|
pbRaw += sizeof( DWORD );
|
|
|
|
ContextHandle->ResumeId = (DWORD_PTR) ( pbRaw + ROUNDUP4( dwStrLen ) );
|
|
|
|
return RtlNtStatusToDosError(ntstatus);
|
|
}
|
|
|
|
|
|
BYTE
|
|
NwGetSubTreeData(
|
|
IN DWORD_PTR NdsRawDataPtr,
|
|
OUT LPWSTR * SubTreeName,
|
|
OUT LPDWORD ResourceScope,
|
|
OUT LPDWORD ResourceType,
|
|
OUT LPDWORD ResourceDisplayType,
|
|
OUT LPDWORD ResourceUsage,
|
|
OUT LPWSTR * StrippedObjectName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by NwEnumNdsSubTrees to get the information
|
|
needed to describe a single NETRESOURCE from an entry in the
|
|
NdsRawDataBuffer.
|
|
|
|
Arguments:
|
|
|
|
NdsRawDataPtr - Supplies the pointer to a buffer with the NDS raw data.
|
|
|
|
SubTreeName - Receives a pointer to the returned subtree object name
|
|
found in buffer.
|
|
|
|
ResourceScope - Receives the value of the scope for the subtree object
|
|
found in buffer.
|
|
|
|
ResourceType - Receives the value of the type for the subtree object
|
|
found in buffer.
|
|
|
|
ResourceDisplayType - Receives the value of the display type for the
|
|
subtree object found in buffer.
|
|
|
|
ResourceUsage - Receives the value of the usage for the subtree object
|
|
found in buffer.
|
|
|
|
StrippedObjectName - A pointer to receive the address of a buffer which
|
|
will contain the formatted object name. Callee must
|
|
free buffer with LocalFree().
|
|
|
|
Return Value:
|
|
|
|
A DWORD with a value that is used to represent NDS object class type..
|
|
|
|
--*/ // NwGetSubTreeData
|
|
{
|
|
PNDS_RESPONSE_SUBORDINATE_ENTRY pSubEntry =
|
|
(PNDS_RESPONSE_SUBORDINATE_ENTRY) NdsRawDataPtr;
|
|
PBYTE pbRaw;
|
|
DWORD dwStrLen;
|
|
LPWSTR ClassNameStr;
|
|
|
|
pbRaw = (BYTE *) pSubEntry;
|
|
|
|
//
|
|
// The structure of a NDS_RESPONSE_SUBORDINATE_ENTRY consists of 4 DWORDs
|
|
// followed by two standard NDS format UNICODE strings. Below we jump pbRaw
|
|
// into the buffer, past the 4 DWORDs.
|
|
//
|
|
pbRaw += sizeof( NDS_RESPONSE_SUBORDINATE_ENTRY );
|
|
|
|
//
|
|
// Now we get the length of the first string (Base Class).
|
|
//
|
|
dwStrLen = * (DWORD *) pbRaw;
|
|
|
|
//
|
|
// Now we point pbRaw to the first WCHAR of the first string (Base Class).
|
|
//
|
|
pbRaw += sizeof( DWORD_PTR );
|
|
|
|
ClassNameStr = (LPWSTR) pbRaw;
|
|
|
|
//
|
|
// Move pbRaw into the buffer, past the first UNICODE string (WORD aligned)
|
|
//
|
|
pbRaw += ROUNDUP4( dwStrLen );
|
|
|
|
//
|
|
// Now we get the length of the second string (Entry Name).
|
|
//
|
|
dwStrLen = * (DWORD *) pbRaw;
|
|
|
|
//
|
|
// Now we point pbRaw to the first WCHAR of the second string (Entry Name).
|
|
//
|
|
pbRaw += sizeof( DWORD_PTR );
|
|
|
|
*SubTreeName = (LPWSTR) pbRaw;
|
|
|
|
//
|
|
// Strip off any CN= stuff from the object name.
|
|
//
|
|
NwStripNdsUncName( *SubTreeName, StrippedObjectName );
|
|
|
|
*ResourceScope = RESOURCE_GLOBALNET;
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_ALIAS ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_ALIAS;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_AFP_SERVER ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_AFP_SERVER;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_BINDERY_OBJECT ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_BINDERY_OBJECT;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_BINDERY_QUEUE ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_BINDERY_QUEUE;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_COMPUTER ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_COMPUTER;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_COUNTRY ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_NDSCONTAINER;
|
|
*ResourceUsage = RESOURCEUSAGE_CONTAINER;
|
|
|
|
return CLASS_TYPE_COUNTRY;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_DIRECTORY_MAP ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_DISK;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
|
|
#ifdef NT1057
|
|
*ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_CONTAINER;
|
|
#else
|
|
*ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_NOLOCALDEVICE;
|
|
#endif
|
|
|
|
return CLASS_TYPE_DIRECTORY_MAP;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_GROUP ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GROUP;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_GROUP;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_LOCALITY ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_LOCALITY;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_NCP_SERVER ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_SERVER;
|
|
*ResourceUsage = RESOURCEUSAGE_CONTAINER;
|
|
|
|
return CLASS_TYPE_NCP_SERVER;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_ORGANIZATION ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_NDSCONTAINER;
|
|
*ResourceUsage = RESOURCEUSAGE_CONTAINER;
|
|
|
|
return CLASS_TYPE_ORGANIZATION;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_ORGANIZATIONAL_ROLE ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_ORGANIZATIONAL_ROLE;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_ORGANIZATIONAL_UNIT ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_NDSCONTAINER;
|
|
*ResourceUsage = RESOURCEUSAGE_CONTAINER;
|
|
|
|
return CLASS_TYPE_ORGANIZATIONAL_UNIT;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_PRINTER ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_PRINT;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
|
|
*ResourceUsage = RESOURCEUSAGE_CONNECTABLE;
|
|
|
|
return CLASS_TYPE_PRINTER;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_PRINT_SERVER ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_PRINT;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_SERVER;
|
|
*ResourceUsage = RESOURCEUSAGE_CONTAINER;
|
|
|
|
return CLASS_TYPE_PRINT_SERVER;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_PROFILE ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_PROFILE;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_QUEUE ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_PRINT;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
|
|
*ResourceUsage = RESOURCEUSAGE_CONNECTABLE;
|
|
|
|
return CLASS_TYPE_QUEUE;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_TOP ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_TOP;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_USER ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_USER;
|
|
}
|
|
|
|
if ( !wcscmp( ClassNameStr, CLASS_NAME_VOLUME ) )
|
|
{
|
|
*ResourceType = RESOURCETYPE_DISK;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
|
|
#ifdef NT1057
|
|
*ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_CONTAINER;
|
|
#else
|
|
*ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_NOLOCALDEVICE;
|
|
#endif
|
|
|
|
return CLASS_TYPE_VOLUME;
|
|
}
|
|
|
|
//
|
|
// Otherwise if ClassNameStr is something other than Unknown, report it
|
|
//
|
|
if ( wcscmp( ClassNameStr, CLASS_NAME_UNKNOWN ) )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwGetSubTreeData failed to recognize"));
|
|
KdPrint((" ClassName: %S\n", ClassNameStr));
|
|
KdPrint((" Setting object attributes to Unknown for now . . .\n"));
|
|
}
|
|
|
|
*ResourceType = RESOURCETYPE_ANY;
|
|
*ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
*ResourceUsage = 0;
|
|
|
|
return CLASS_TYPE_UNKNOWN;
|
|
}
|
|
|
|
|
|
VOID
|
|
NwStripNdsUncName(
|
|
IN LPWSTR ObjectName,
|
|
OUT LPWSTR * StrippedObjectName
|
|
)
|
|
{
|
|
WORD slashCount;
|
|
BOOL isNdsUnc;
|
|
LPWSTR FourthSlash;
|
|
LPWSTR TreeName;
|
|
LPWSTR ObjectPath;
|
|
DWORD TreeNameLen;
|
|
DWORD ObjectPathLen;
|
|
DWORD PrefixBytes;
|
|
DWORD CurrentPathIndex;
|
|
DWORD StrippedNameLen;
|
|
DWORD StrippedNameMaxLen = MAX_NDS_NAME_CHARS;
|
|
WCHAR StrippedName[MAX_NDS_NAME_CHARS];
|
|
|
|
*StrippedObjectName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
|
|
(wcslen(ObjectName) + 1) *
|
|
sizeof(WCHAR) );
|
|
|
|
if ( *StrippedObjectName == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
NwpGetUncInfo( ObjectName, &slashCount, &isNdsUnc, &FourthSlash );
|
|
|
|
if ( slashCount >= 2 )
|
|
{
|
|
TreeNameLen = NwParseNdsUncPath( &TreeName,
|
|
ObjectName,
|
|
PARSE_NDS_GET_TREE_NAME );
|
|
|
|
TreeNameLen /= sizeof(WCHAR);
|
|
|
|
wcscpy( *StrippedObjectName, L"\\\\" );
|
|
wcsncat( *StrippedObjectName, TreeName, TreeNameLen );
|
|
|
|
ObjectPathLen = NwParseNdsUncPath( &ObjectPath,
|
|
ObjectName,
|
|
PARSE_NDS_GET_PATH_NAME );
|
|
|
|
if ( ObjectPathLen == 0 )
|
|
{
|
|
_wcsupr( *StrippedObjectName );
|
|
|
|
return;
|
|
}
|
|
|
|
wcscat( *StrippedObjectName, L"\\" );
|
|
}
|
|
else
|
|
{
|
|
wcscpy( *StrippedObjectName, L"" );
|
|
|
|
ObjectPath = ObjectName;
|
|
ObjectPathLen = wcslen(ObjectName) * sizeof(WCHAR);
|
|
}
|
|
|
|
CurrentPathIndex = 0;
|
|
PrefixBytes = 0;
|
|
StrippedNameLen = 0;
|
|
|
|
//
|
|
// All of these indexes are in BYTES, not WCHARS!
|
|
//
|
|
while ( ( CurrentPathIndex < ObjectPathLen ) &&
|
|
( StrippedNameLen < StrippedNameMaxLen ) )
|
|
{
|
|
if ( ObjectPath[CurrentPathIndex / sizeof( WCHAR )] == L'=' )
|
|
{
|
|
CurrentPathIndex += sizeof( WCHAR );
|
|
StrippedNameLen -= PrefixBytes;
|
|
PrefixBytes = 0;
|
|
|
|
continue;
|
|
}
|
|
|
|
StrippedName[StrippedNameLen / sizeof( WCHAR )] =
|
|
ObjectPath[CurrentPathIndex / sizeof( WCHAR )];
|
|
|
|
StrippedNameLen += sizeof( WCHAR );
|
|
CurrentPathIndex += sizeof( WCHAR );
|
|
|
|
if ( ObjectPath[CurrentPathIndex / sizeof( WCHAR )] == L'.' )
|
|
{
|
|
PrefixBytes = 0;
|
|
PrefixBytes -= sizeof( WCHAR );
|
|
}
|
|
else
|
|
{
|
|
PrefixBytes += sizeof( WCHAR );
|
|
}
|
|
}
|
|
|
|
StrippedName[StrippedNameLen / sizeof( WCHAR )] = L'\0';
|
|
|
|
wcscat( *StrippedObjectName, StrippedName );
|
|
_wcsupr( *StrippedObjectName );
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwVerifyNDSObject(
|
|
IN LPWSTR lpNDSObjectNamePath,
|
|
OUT LPWSTR * lpFullNDSObjectNamePath,
|
|
OUT LPDWORD lpClassType,
|
|
OUT LPDWORD lpResourceScope,
|
|
OUT LPDWORD lpResourceType,
|
|
OUT LPDWORD lpResourceDisplayType,
|
|
OUT LPDWORD lpResourceUsage
|
|
)
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
NTSTATUS ntstatus = STATUS_SUCCESS;
|
|
UNICODE_STRING TreeServerName;
|
|
UNICODE_STRING PathString;
|
|
HANDLE ConnectionHandle = NULL;
|
|
DWORD dwHandleType;
|
|
DWORD dwOid;
|
|
BOOL fImpersonate = FALSE ;
|
|
|
|
if ( lpNDSObjectNamePath == NULL )
|
|
{
|
|
//
|
|
// Handle this as if we are at the root of our provider hierarchy.
|
|
//
|
|
*lpResourceScope = RESOURCE_GLOBALNET;
|
|
*lpResourceType = RESOURCETYPE_ANY;
|
|
#ifdef NT1057
|
|
*lpResourceDisplayType = 0;
|
|
#else
|
|
*lpResourceDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
|
|
#endif
|
|
*lpResourceUsage = RESOURCEUSAGE_CONTAINER;
|
|
|
|
*lpFullNDSObjectNamePath = NULL;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
TreeServerName.Buffer = NULL;
|
|
PathString.Buffer = NULL;
|
|
TreeServerName.MaximumLength = ( wcslen( lpNDSObjectNamePath ) + 1 ) * sizeof( WCHAR );
|
|
PathString.MaximumLength = ( wcslen( lpNDSObjectNamePath ) + 1 ) * sizeof( WCHAR );
|
|
|
|
TreeServerName.Length = NwParseNdsUncPath( (LPWSTR *) &TreeServerName.Buffer,
|
|
lpNDSObjectNamePath,
|
|
PARSE_NDS_GET_TREE_NAME );
|
|
|
|
if ( TreeServerName.Length == 0 || TreeServerName.Buffer == NULL )
|
|
{
|
|
//
|
|
// lpNDSObjectNamePath is not in the form \\name[\blah.blah.blah][\foo][\bar]...
|
|
//
|
|
status = WN_BAD_NETNAME;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Impersonate the client
|
|
//
|
|
if ( ( status = NwImpersonateClient() ) != NO_ERROR )
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
fImpersonate = TRUE;
|
|
|
|
//
|
|
// Open a connection handle to \\name
|
|
//
|
|
ntstatus = NwNdsOpenGenericHandle( &TreeServerName,
|
|
&dwHandleType,
|
|
&ConnectionHandle );
|
|
|
|
if ( ntstatus != STATUS_SUCCESS )
|
|
{
|
|
//
|
|
// The first part of lpNDSObjectNamePath was neither a NDS tree nor a NCP Server.
|
|
//
|
|
status = WN_BAD_NETNAME;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if ( dwHandleType != HANDLE_TYPE_NDS_TREE )
|
|
{
|
|
//
|
|
// The first part of lpNDSObjectNamePath was not a NDS tree.
|
|
//
|
|
status = VERIFY_ERROR_NOT_A_NDS_TREE;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Adjust TreeServerName.Length to number of characters.
|
|
//
|
|
TreeServerName.Length /= sizeof(WCHAR);
|
|
|
|
//
|
|
// The lpNDSObjectNamePath points to a NDS tree. Now verify that the path is valid.
|
|
//
|
|
PathString.Length = NwParseNdsUncPath( (LPWSTR *) &PathString.Buffer,
|
|
lpNDSObjectNamePath,
|
|
PARSE_NDS_GET_PATH_NAME );
|
|
|
|
if ( PathString.Length == 0 )
|
|
{
|
|
LPWSTR treeNameStr = NULL;
|
|
|
|
if ( fImpersonate )
|
|
(void) NwRevertToSelf() ;
|
|
|
|
if ( ConnectionHandle )
|
|
CloseHandle( ConnectionHandle );
|
|
|
|
*lpResourceScope = RESOURCE_GLOBALNET;
|
|
*lpResourceType = RESOURCETYPE_ANY;
|
|
*lpResourceDisplayType = RESOURCEDISPLAYTYPE_TREE;
|
|
*lpResourceUsage = RESOURCEUSAGE_CONTAINER;
|
|
|
|
//
|
|
// Need to build a string with the new NDS UNC path for subtree object
|
|
//
|
|
treeNameStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
|
|
( TreeServerName.Length + 3 ) * sizeof(WCHAR) );
|
|
|
|
if ( treeNameStr == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wcscpy( treeNameStr, L"\\\\" );
|
|
wcsncat( treeNameStr, TreeServerName.Buffer, TreeServerName.Length );
|
|
_wcsupr( treeNameStr );
|
|
|
|
*lpFullNDSObjectNamePath = treeNameStr;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
WCHAR lpServerName[NW_MAX_SERVER_LEN];
|
|
UNICODE_STRING ServerName;
|
|
|
|
ServerName.Length = 0;
|
|
ServerName.MaximumLength = sizeof( lpServerName );
|
|
ServerName.Buffer = lpServerName;
|
|
|
|
//
|
|
// Resolve the path to get a NDS object id.
|
|
//
|
|
ntstatus = NwNdsResolveName( ConnectionHandle,
|
|
&PathString,
|
|
&dwOid,
|
|
&ServerName,
|
|
NULL,
|
|
0 );
|
|
|
|
if ( ntstatus == STATUS_SUCCESS && ServerName.Length )
|
|
{
|
|
DWORD dwHandleType;
|
|
|
|
//
|
|
// NwNdsResolveName succeeded, but we were referred to
|
|
// another server, though ContextHandle->dwOid is still valid.
|
|
|
|
if ( ConnectionHandle )
|
|
CloseHandle( ConnectionHandle );
|
|
|
|
ConnectionHandle = NULL;
|
|
|
|
//
|
|
// Open a NDS generic connection handle to \\ServerName
|
|
//
|
|
ntstatus = NwNdsOpenGenericHandle( &ServerName,
|
|
&dwHandleType,
|
|
&ConnectionHandle );
|
|
|
|
if ( ntstatus != STATUS_SUCCESS )
|
|
{
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
ASSERT( dwHandleType != HANDLE_TYPE_NCP_SERVER );
|
|
}
|
|
}
|
|
|
|
if ( ntstatus != STATUS_SUCCESS )
|
|
{
|
|
LPWSTR treeNameStr = NULL;
|
|
|
|
*lpResourceScope = RESOURCE_GLOBALNET;
|
|
*lpResourceType = RESOURCETYPE_ANY;
|
|
*lpResourceDisplayType = RESOURCEDISPLAYTYPE_TREE;
|
|
*lpResourceUsage = RESOURCEUSAGE_CONTAINER;
|
|
|
|
//
|
|
// Need to build a string with the new NDS UNC path for subtree object
|
|
//
|
|
treeNameStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
|
|
( TreeServerName.Length + 3 ) * sizeof(WCHAR) );
|
|
|
|
if ( treeNameStr == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wcscpy( treeNameStr, L"\\\\" );
|
|
wcsncat( treeNameStr, TreeServerName.Buffer, TreeServerName.Length );
|
|
_wcsupr( treeNameStr );
|
|
|
|
*lpFullNDSObjectNamePath = treeNameStr;
|
|
|
|
status = VERIFY_ERROR_PATH_NOT_FOUND;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Check to see what kind of object is pointed to by lpRemoteName.
|
|
//
|
|
{
|
|
BYTE RawResponse[TWO_KB];
|
|
PBYTE pbRawGetInfo;
|
|
DWORD RawResponseSize = sizeof(RawResponse);
|
|
DWORD dwStrLen;
|
|
LPWSTR TreeObjectName;
|
|
LPWSTR StrippedObjectName = NULL;
|
|
LPWSTR newPathStr = NULL;
|
|
|
|
ntstatus = NwNdsReadObjectInfo( ConnectionHandle,
|
|
dwOid,
|
|
RawResponse,
|
|
RawResponseSize );
|
|
|
|
if ( ntstatus != NO_ERROR )
|
|
{
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get current subtree data from ContextHandle
|
|
//
|
|
*lpClassType = NwGetSubTreeData( (DWORD_PTR) RawResponse,
|
|
&TreeObjectName,
|
|
lpResourceScope,
|
|
lpResourceType,
|
|
lpResourceDisplayType,
|
|
lpResourceUsage,
|
|
&StrippedObjectName );
|
|
|
|
if ( StrippedObjectName == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Need to build a string with the new NDS UNC path for subtree object
|
|
//
|
|
newPathStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
|
|
( wcslen( StrippedObjectName ) +
|
|
TreeServerName.Length + 4 )
|
|
* sizeof(WCHAR) );
|
|
|
|
if ( newPathStr == NULL )
|
|
{
|
|
(void) LocalFree((HLOCAL) StrippedObjectName);
|
|
|
|
KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wcscpy( newPathStr, L"\\\\" );
|
|
wcsncat( newPathStr, TreeServerName.Buffer, TreeServerName.Length );
|
|
wcscat( newPathStr, L"\\" );
|
|
wcscat( newPathStr, StrippedObjectName );
|
|
_wcsupr( newPathStr );
|
|
|
|
//
|
|
// Don't need the StrippedObjectName string anymore
|
|
//
|
|
(void) LocalFree((HLOCAL) StrippedObjectName);
|
|
StrippedObjectName = NULL;
|
|
|
|
*lpFullNDSObjectNamePath = newPathStr;
|
|
status = NO_ERROR;
|
|
} // End of Block
|
|
|
|
ErrorExit:
|
|
|
|
if ( fImpersonate )
|
|
(void) NwRevertToSelf() ;
|
|
|
|
if ( ConnectionHandle )
|
|
CloseHandle( ConnectionHandle );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwVerifyBinderyObject(
|
|
IN LPWSTR lpBinderyObjectPathName,
|
|
OUT LPWSTR * lpFullBinderyObjectPathName,
|
|
OUT LPDWORD lpClassType,
|
|
OUT LPDWORD lpResourceScope,
|
|
OUT LPDWORD lpResourceType,
|
|
OUT LPDWORD lpResourceDisplayType,
|
|
OUT LPDWORD lpResourceUsage
|
|
)
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
HANDLE ConnectionHandle = NULL;
|
|
BOOL fImpersonate = FALSE ;
|
|
BOOL fResourceTypeDisk = FALSE ;
|
|
BOOL fIsNdsUnc = FALSE ;
|
|
UNICODE_STRING BinderyConnectStr;
|
|
ULONG CreateDisposition = 0;
|
|
ULONG CreateOptions = 0;
|
|
WORD wSlashCount;
|
|
LPWSTR FourthSlash;
|
|
|
|
if ( lpBinderyObjectPathName == NULL )
|
|
{
|
|
//
|
|
// Handle this as if we are at the root of our provider hierarchy.
|
|
//
|
|
*lpResourceScope = RESOURCE_GLOBALNET;
|
|
*lpResourceType = RESOURCETYPE_ANY;
|
|
#ifdef NT1057
|
|
*lpResourceDisplayType = 0;
|
|
#else
|
|
*lpResourceDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
|
|
#endif
|
|
*lpResourceUsage = RESOURCEUSAGE_CONTAINER;
|
|
|
|
*lpFullBinderyObjectPathName = NULL;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Open a connection handle to \\server\vol\...
|
|
//
|
|
|
|
BinderyConnectStr.Buffer = NULL;
|
|
|
|
//
|
|
// Find out if we are looking at a \\server, \\server\vol, or
|
|
// \\server\vol\dir . . .
|
|
//
|
|
NwpGetUncInfo( lpBinderyObjectPathName,
|
|
&wSlashCount,
|
|
&fIsNdsUnc,
|
|
&FourthSlash );
|
|
|
|
if ( wSlashCount > 2 )
|
|
fResourceTypeDisk = TRUE;
|
|
|
|
//
|
|
// Impersonate the client
|
|
//
|
|
if ( ( status = NwImpersonateClient() ) != NO_ERROR )
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
fImpersonate = TRUE;
|
|
|
|
//
|
|
// Open a tree connection handle to \Device\NwRdr\ContainerName
|
|
//
|
|
status = NwCreateTreeConnectName( lpBinderyObjectPathName,
|
|
NULL,
|
|
&BinderyConnectStr );
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
status = WN_BAD_NETNAME;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CreateDisposition = FILE_OPEN;
|
|
CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT;
|
|
|
|
status = NwOpenCreateConnection( &BinderyConnectStr,
|
|
NULL,
|
|
NULL,
|
|
lpBinderyObjectPathName,
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
CreateDisposition,
|
|
CreateOptions,
|
|
RESOURCETYPE_DISK, // When connecting beyond servername
|
|
&ConnectionHandle,
|
|
NULL );
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
LPWSTR BinderyNameStr = NULL;
|
|
|
|
//
|
|
// Need to build a string with the new UNC path for bindery object
|
|
//
|
|
BinderyNameStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
|
|
( wcslen( lpBinderyObjectPathName ) + 1 )
|
|
* sizeof(WCHAR) );
|
|
|
|
if ( BinderyNameStr == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwVerifyBinderyObject LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wcscpy( BinderyNameStr, lpBinderyObjectPathName );
|
|
_wcsupr( BinderyNameStr );
|
|
|
|
*lpFullBinderyObjectPathName = BinderyNameStr;
|
|
|
|
if ( BinderyConnectStr.Buffer )
|
|
(void) LocalFree((HLOCAL) BinderyConnectStr.Buffer);
|
|
|
|
if ( fImpersonate )
|
|
(void) NwRevertToSelf() ;
|
|
|
|
if ( ConnectionHandle )
|
|
{
|
|
*lpResourceScope = RESOURCE_GLOBALNET;
|
|
*lpResourceType = fResourceTypeDisk ?
|
|
RESOURCETYPE_DISK :
|
|
RESOURCETYPE_ANY;
|
|
*lpResourceDisplayType = fResourceTypeDisk ?
|
|
RESOURCEDISPLAYTYPE_SHARE :
|
|
RESOURCEDISPLAYTYPE_SERVER;
|
|
#ifdef NT1057
|
|
*lpResourceUsage = fResourceTypeDisk ?
|
|
RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_CONTAINER :
|
|
RESOURCEUSAGE_CONTAINER;
|
|
#else
|
|
*lpResourceUsage = fResourceTypeDisk ?
|
|
RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_NOLOCALDEVICE :
|
|
RESOURCEUSAGE_CONTAINER;
|
|
#endif
|
|
|
|
CloseHandle( ConnectionHandle );
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
ErrorExit:
|
|
|
|
*lpFullBinderyObjectPathName = NULL;
|
|
|
|
if ( BinderyConnectStr.Buffer )
|
|
(void) LocalFree((HLOCAL) BinderyConnectStr.Buffer);
|
|
|
|
if ( fImpersonate )
|
|
(void) NwRevertToSelf() ;
|
|
|
|
if ( ConnectionHandle )
|
|
CloseHandle( ConnectionHandle );
|
|
|
|
return WN_BAD_NETNAME;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwGetNDSPathInfo(
|
|
IN LPWSTR lpNDSObjectNamePath,
|
|
OUT LPWSTR * lppSystemObjectNamePath,
|
|
OUT LPWSTR * lpSystemPathPart,
|
|
OUT LPDWORD lpClassType,
|
|
OUT LPDWORD lpResourceScope,
|
|
OUT LPDWORD lpResourceType,
|
|
OUT LPDWORD lpResourceDisplayType,
|
|
OUT LPDWORD lpResourceUsage
|
|
)
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
WORD slashCount;
|
|
BOOL isNdsUnc;
|
|
BOOL fReturnBadNetName = FALSE;
|
|
LPWSTR FourthSlash;
|
|
LPWSTR lpSystemPath = NULL;
|
|
|
|
*lpSystemPathPart = NULL;
|
|
|
|
NwpGetUncInfo( lpNDSObjectNamePath,
|
|
&slashCount,
|
|
&isNdsUnc,
|
|
&FourthSlash );
|
|
|
|
if ( slashCount <= 3 )
|
|
{
|
|
//
|
|
// Path is to a possible NDS object, check to see if so and if valid...
|
|
//
|
|
|
|
status = NwVerifyNDSObject( lpNDSObjectNamePath,
|
|
lppSystemObjectNamePath,
|
|
lpClassType,
|
|
lpResourceScope,
|
|
lpResourceType,
|
|
lpResourceDisplayType,
|
|
lpResourceUsage );
|
|
|
|
*lpSystemPathPart = NULL;
|
|
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Path is to a directory, see if directory exists . . .
|
|
//
|
|
status = NwVerifyBinderyObject( lpNDSObjectNamePath,
|
|
lppSystemObjectNamePath,
|
|
lpClassType,
|
|
lpResourceScope,
|
|
lpResourceType,
|
|
lpResourceDisplayType,
|
|
lpResourceUsage );
|
|
}
|
|
|
|
if ( status == WN_BAD_NETNAME )
|
|
{
|
|
fReturnBadNetName = TRUE;
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
WCHAR TempNDSObjectNamePath[256];
|
|
|
|
//
|
|
// Test \\tree\obj.obj... component and
|
|
// return network resource for valid parent and the string,
|
|
// lpSystemPathPart, for the directory part ( \dir1\...).
|
|
//
|
|
|
|
if ( *lppSystemObjectNamePath != NULL )
|
|
{
|
|
(void) LocalFree( (HLOCAL) (*lppSystemObjectNamePath) );
|
|
*lppSystemObjectNamePath = NULL;
|
|
}
|
|
|
|
lpSystemPath = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
|
|
( wcslen( FourthSlash ) + 1 ) *
|
|
sizeof( WCHAR ) );
|
|
|
|
if ( lpSystemPath == NULL )
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
wcscpy( lpSystemPath, FourthSlash );
|
|
*FourthSlash = L'\0';
|
|
|
|
wcscpy( TempNDSObjectNamePath, lpNDSObjectNamePath );
|
|
*FourthSlash = L'\\';
|
|
|
|
//
|
|
// See if \\tree\obj.obj.... exists . . .
|
|
//
|
|
status = NwVerifyNDSObject( TempNDSObjectNamePath,
|
|
lppSystemObjectNamePath,
|
|
lpClassType,
|
|
lpResourceScope,
|
|
lpResourceType,
|
|
lpResourceDisplayType,
|
|
lpResourceUsage );
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
LocalFree( lpSystemPath );
|
|
lpSystemPath = NULL;
|
|
}
|
|
}
|
|
|
|
*lpSystemPathPart = lpSystemPath;
|
|
|
|
//
|
|
// The provider spec for this function used to tell us to create a
|
|
// NETRESOURCE, even if the system part of the path was invalid, while
|
|
// returning WN_BAD_NETNAME. Now we return SUCCESS and the NETRESOURCE,
|
|
// irregardless of whether the lpSystem part is valid.
|
|
// if ( fReturnBadNetName == TRUE )
|
|
// {
|
|
// return WN_BAD_NETNAME;
|
|
// }
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwGetBinderyPathInfo(
|
|
IN LPWSTR lpBinderyObjectNamePath,
|
|
OUT LPWSTR * lppSystemObjectNamePath,
|
|
OUT LPWSTR * lpSystemPathPart,
|
|
OUT LPDWORD lpClassType,
|
|
OUT LPDWORD lpResourceScope,
|
|
OUT LPDWORD lpResourceType,
|
|
OUT LPDWORD lpResourceDisplayType,
|
|
OUT LPDWORD lpResourceUsage
|
|
)
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
WORD slashCount;
|
|
BOOL isNdsUnc;
|
|
LPWSTR FourthSlash;
|
|
LPWSTR lpSystemPath = NULL;
|
|
|
|
*lpSystemPathPart = NULL;
|
|
|
|
NwpGetUncInfo( lpBinderyObjectNamePath,
|
|
&slashCount,
|
|
&isNdsUnc,
|
|
&FourthSlash );
|
|
|
|
if ( slashCount <= 3 )
|
|
{
|
|
//
|
|
// Path is to a server or volume, check to see which and if valid . . .
|
|
//
|
|
|
|
status = NwVerifyBinderyObject( lpBinderyObjectNamePath,
|
|
lppSystemObjectNamePath,
|
|
lpClassType,
|
|
lpResourceScope,
|
|
lpResourceType,
|
|
lpResourceDisplayType,
|
|
lpResourceUsage );
|
|
|
|
*lpSystemPathPart = NULL;
|
|
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Path is to a directory, see if directory exists . . .
|
|
//
|
|
status = NwVerifyBinderyObject( lpBinderyObjectNamePath,
|
|
lppSystemObjectNamePath,
|
|
lpClassType,
|
|
lpResourceScope,
|
|
lpResourceType,
|
|
lpResourceDisplayType,
|
|
lpResourceUsage );
|
|
}
|
|
|
|
if ( status == WN_BAD_NETNAME )
|
|
{
|
|
WCHAR TempBinderyObjectNamePath[256];
|
|
|
|
//
|
|
// Path is to a invalid directory. Test \\server\volume component and
|
|
// return network resource for valid parent and the string,
|
|
// lpSystemPathPart, for the directory part ( \dir1\...).
|
|
//
|
|
|
|
lpSystemPath = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
|
|
( wcslen( FourthSlash ) + 1 ) *
|
|
sizeof( WCHAR ) );
|
|
|
|
if ( lpSystemPath == NULL )
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
wcscpy( lpSystemPath, FourthSlash );
|
|
*FourthSlash = L'\0';
|
|
|
|
wcscpy( TempBinderyObjectNamePath, lpBinderyObjectNamePath );
|
|
*FourthSlash = L'\\';
|
|
|
|
//
|
|
// See if \\server\volume exists . . .
|
|
//
|
|
status = NwVerifyBinderyObject( TempBinderyObjectNamePath,
|
|
lppSystemObjectNamePath,
|
|
lpClassType,
|
|
lpResourceScope,
|
|
lpResourceType,
|
|
lpResourceDisplayType,
|
|
lpResourceUsage );
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
LocalFree( lpSystemPath );
|
|
lpSystemPath = NULL;
|
|
}
|
|
|
|
//
|
|
// Return SUCCESS, since the NETRESOURCE for \\server\volume that
|
|
// we are describing is at least valid, even though the lpSystem
|
|
// part in not. This is a change in the provider spec (4/25/96).
|
|
//
|
|
// else
|
|
// {
|
|
// status = WN_BAD_NETNAME;
|
|
// }
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Path is to a valid directory. Return resource information for the
|
|
// \\server\volume component and the string, lpSystemPathPart, for the
|
|
// directory part ( \dir1\...).
|
|
//
|
|
NwpGetUncInfo( *lppSystemObjectNamePath,
|
|
&slashCount,
|
|
&isNdsUnc,
|
|
&FourthSlash );
|
|
|
|
lpSystemPath = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
|
|
( wcslen( FourthSlash ) + 1 ) *
|
|
sizeof( WCHAR ) );
|
|
|
|
if ( lpSystemPath == NULL )
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
wcscpy( lpSystemPath, FourthSlash );
|
|
*FourthSlash = L'\0';
|
|
|
|
*lpResourceScope = RESOURCE_GLOBALNET;
|
|
*lpResourceType = RESOURCETYPE_DISK;
|
|
*lpResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
|
|
#ifdef NT1057
|
|
*lpResourceUsage = RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_CONTAINER;
|
|
#else
|
|
*lpResourceUsage = RESOURCEUSAGE_CONNECTABLE |
|
|
RESOURCEUSAGE_NOLOCALDEVICE;
|
|
#endif
|
|
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
*lpSystemPathPart = lpSystemPath;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
BOOL
|
|
NwGetRemoteNameParent(
|
|
IN LPWSTR lpRemoteName,
|
|
OUT LPWSTR * lpRemoteNameParent
|
|
)
|
|
{
|
|
unsigned short iter = 0;
|
|
unsigned short totalLength = (USHORT) wcslen( lpRemoteName );
|
|
unsigned short slashCount = 0;
|
|
unsigned short dotCount = 0;
|
|
unsigned short thirdSlash = 0;
|
|
unsigned short lastSlash = 0;
|
|
unsigned short parentNDSSubTree = 0;
|
|
LPWSTR newRemoteNameParent = NULL;
|
|
|
|
if ( totalLength < 2 )
|
|
return FALSE;
|
|
|
|
//
|
|
// Get thirdSlash to indicate the character in the string that indicates the
|
|
// "\" in between the tree name and the rest of the UNC path. Set parentNDSSubTree
|
|
// if available. And always set lastSlash to the most recent "\" seen as you walk.
|
|
//
|
|
// Example: \\<tree name>\path.to.object[\|.]<object>
|
|
// ^ ^
|
|
// | |
|
|
// thirdSlash parentNDSSubTree
|
|
//
|
|
while ( iter < totalLength )
|
|
{
|
|
if ( lpRemoteName[iter] == L'\\' )
|
|
{
|
|
slashCount += 1;
|
|
if ( slashCount == 3 )
|
|
thirdSlash = iter;
|
|
|
|
lastSlash = iter;
|
|
}
|
|
|
|
if ( lpRemoteName[iter] == L'.' )
|
|
{
|
|
dotCount += 1;
|
|
if ( dotCount == 1 )
|
|
parentNDSSubTree = iter;
|
|
}
|
|
|
|
iter++;
|
|
}
|
|
|
|
if ( slashCount > 3 )
|
|
{
|
|
newRemoteNameParent = (PVOID) LocalAlloc( LMEM_ZEROINIT,
|
|
( lastSlash + 1 ) *
|
|
sizeof(WCHAR));
|
|
|
|
if ( newRemoteNameParent == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwGetRemoteNameParent LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
wcsncpy( newRemoteNameParent, lpRemoteName, lastSlash );
|
|
_wcsupr( newRemoteNameParent );
|
|
|
|
*lpRemoteNameParent = newRemoteNameParent;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if ( slashCount == 3 )
|
|
{
|
|
if ( dotCount == 0 )
|
|
{
|
|
newRemoteNameParent = (PVOID) LocalAlloc( LMEM_ZEROINIT,
|
|
( lastSlash + 1 ) *
|
|
sizeof(WCHAR));
|
|
|
|
if ( newRemoteNameParent == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwGetRemoteNameParent LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
wcsncpy( newRemoteNameParent, lpRemoteName, lastSlash );
|
|
_wcsupr( newRemoteNameParent );
|
|
|
|
*lpRemoteNameParent = newRemoteNameParent;
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
newRemoteNameParent = (PVOID) LocalAlloc( LMEM_ZEROINIT,
|
|
( totalLength -
|
|
( parentNDSSubTree - thirdSlash )
|
|
+ 1 )
|
|
* sizeof(WCHAR) );
|
|
|
|
if ( newRemoteNameParent == NULL )
|
|
{
|
|
KdPrint(("NWWORKSTATION: NwGetRemoteNameParent LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
wcsncpy( newRemoteNameParent, lpRemoteName, thirdSlash + 1 );
|
|
wcscat( newRemoteNameParent, &lpRemoteName[parentNDSSubTree+1] );
|
|
_wcsupr( newRemoteNameParent );
|
|
|
|
*lpRemoteNameParent = newRemoteNameParent;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Else we set lpRemoteNameParent to NULL, to indicate that we are at the top and
|
|
// return TRUE.
|
|
*lpRemoteNameParent = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwGetFirstDirectoryEntry(
|
|
IN HANDLE DirHandle,
|
|
OUT LPWSTR *DirEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by NwEnumDirectories to get the first
|
|
directory entry given a handle to the directory. It allocates
|
|
the output buffer to hold the returned directory name; the
|
|
caller should free this output buffer with LocalFree when done.
|
|
|
|
Arguments:
|
|
|
|
DirHandle - Supplies the opened handle to the container
|
|
directory find a directory within it.
|
|
|
|
DirEntry - Receives a pointer to the returned directory
|
|
found.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - The operation was successful.
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
|
|
buffer.
|
|
|
|
Other errors from NtQueryDirectoryFile.
|
|
|
|
--*/ // NwGetFirstDirectoryEntry
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
NTSTATUS ntstatus = STATUS_SUCCESS;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
PFILE_DIRECTORY_INFORMATION DirInfo;
|
|
|
|
UNICODE_STRING StartFileName;
|
|
|
|
#if DBG
|
|
DWORD i = 0;
|
|
#endif
|
|
|
|
//
|
|
// Allocate a large buffer to get one directory information entry.
|
|
//
|
|
DirInfo = (PVOID) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
sizeof(FILE_DIRECTORY_INFORMATION) +
|
|
(MAX_PATH * sizeof(WCHAR))
|
|
);
|
|
|
|
if (DirInfo == NULL) {
|
|
KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RtlInitUnicodeString(&StartFileName, L"*");
|
|
|
|
ntstatus = NtQueryDirectoryFile(
|
|
DirHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
DirInfo,
|
|
sizeof(FILE_DIRECTORY_INFORMATION) +
|
|
(MAX_PATH * sizeof(WCHAR)),
|
|
FileDirectoryInformation, // Info class requested
|
|
TRUE, // Return single entry
|
|
&StartFileName, // Redirector needs this
|
|
TRUE // Restart scan
|
|
);
|
|
|
|
//
|
|
// For now, if buffer to NtQueryDirectoryFile is too small, just give
|
|
// up. We may want to try to reallocate a bigger buffer at a later time.
|
|
//
|
|
|
|
if (ntstatus == STATUS_SUCCESS) {
|
|
ntstatus = IoStatusBlock.Status;
|
|
}
|
|
|
|
if (ntstatus != STATUS_SUCCESS) {
|
|
|
|
if (ntstatus == STATUS_NO_MORE_FILES) {
|
|
//
|
|
// We ran out of entries.
|
|
//
|
|
status = WN_NO_MORE_ENTRIES;
|
|
}
|
|
else {
|
|
KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry: NtQueryDirectoryFile returns %08lx\n",
|
|
ntstatus));
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
}
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("GetFirst(%u) got %ws, attributes %08lx\n", ++i,
|
|
DirInfo->FileName, DirInfo->FileAttributes));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Scan until we find the first directory entry that is not "." or ".."
|
|
//
|
|
while (!(DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
|
|
memcmp(DirInfo->FileName, L".", DirInfo->FileNameLength) == 0 ||
|
|
memcmp(DirInfo->FileName, L"..", DirInfo->FileNameLength) == 0) {
|
|
|
|
ntstatus = NtQueryDirectoryFile(
|
|
DirHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
DirInfo,
|
|
sizeof(FILE_DIRECTORY_INFORMATION) +
|
|
(MAX_PATH * sizeof(WCHAR)),
|
|
FileDirectoryInformation, // Info class requested
|
|
TRUE, // Return single entry
|
|
NULL,
|
|
FALSE // Restart scan
|
|
);
|
|
|
|
if (ntstatus == STATUS_SUCCESS) {
|
|
ntstatus = IoStatusBlock.Status;
|
|
}
|
|
|
|
if (ntstatus != STATUS_SUCCESS) {
|
|
|
|
if (ntstatus == STATUS_NO_MORE_FILES) {
|
|
//
|
|
// We ran out of entries.
|
|
//
|
|
status = WN_NO_MORE_ENTRIES;
|
|
}
|
|
else {
|
|
KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry: NtQueryDirectoryFile returns %08lx\n",
|
|
ntstatus));
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
}
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("GetFirst(%u) got %ws, attributes %08lx\n", ++i,
|
|
DirInfo->FileName, DirInfo->FileAttributes));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Allocate the output buffer for the returned directory name
|
|
//
|
|
*DirEntry = (PVOID) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
DirInfo->FileNameLength + sizeof(WCHAR)
|
|
);
|
|
|
|
if (*DirEntry == NULL) {
|
|
KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto CleanExit;
|
|
}
|
|
|
|
memcpy(*DirEntry, DirInfo->FileName, DirInfo->FileNameLength);
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry returns %ws\n",
|
|
*DirEntry));
|
|
}
|
|
#endif
|
|
|
|
status = NO_ERROR;
|
|
|
|
CleanExit:
|
|
(void) LocalFree((HLOCAL) DirInfo);
|
|
|
|
//
|
|
// We could not find any directories under the requested
|
|
// so we need to treat this as no entries.
|
|
//
|
|
if ( status == ERROR_FILE_NOT_FOUND )
|
|
status = WN_NO_MORE_ENTRIES;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NwGetNextDirectoryEntry(
|
|
IN HANDLE DirHandle,
|
|
OUT LPWSTR *DirEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by NwEnumDirectories to get the next
|
|
directory entry given a handle to the directory. It allocates
|
|
the output buffer to hold the returned directory name; the
|
|
caller should free this output buffer with LocalFree when done.
|
|
|
|
Arguments:
|
|
|
|
DirHandle - Supplies the opened handle to the container
|
|
directory find a directory within it.
|
|
|
|
DirEntry - Receives a pointer to the returned directory
|
|
found.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - The operation was successful.
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
|
|
buffer.
|
|
|
|
Other errors from NtQueryDirectoryFile.
|
|
|
|
--*/ // NwGetNextDirectoryEntry
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
NTSTATUS ntstatus = STATUS_SUCCESS;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
PFILE_DIRECTORY_INFORMATION DirInfo;
|
|
|
|
//
|
|
// Allocate a large buffer to get one directory information entry.
|
|
//
|
|
DirInfo = (PVOID) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
sizeof(FILE_DIRECTORY_INFORMATION) +
|
|
(MAX_PATH * sizeof(WCHAR))
|
|
);
|
|
|
|
if (DirInfo == NULL) {
|
|
KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
do {
|
|
|
|
ntstatus = NtQueryDirectoryFile(
|
|
DirHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
DirInfo,
|
|
sizeof(FILE_DIRECTORY_INFORMATION) +
|
|
(MAX_PATH * sizeof(WCHAR)),
|
|
FileDirectoryInformation, // Info class requested
|
|
TRUE, // Return single entry
|
|
NULL,
|
|
FALSE // Restart scan
|
|
);
|
|
|
|
if (ntstatus == STATUS_SUCCESS) {
|
|
ntstatus = IoStatusBlock.Status;
|
|
}
|
|
|
|
} while (ntstatus == STATUS_SUCCESS &&
|
|
!(DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY));
|
|
|
|
|
|
if (ntstatus != STATUS_SUCCESS) {
|
|
|
|
if (ntstatus == STATUS_NO_MORE_FILES) {
|
|
//
|
|
// We ran out of entries.
|
|
//
|
|
status = WN_NO_MORE_ENTRIES;
|
|
}
|
|
else {
|
|
KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry: NtQueryDirectoryFile returns %08lx\n",
|
|
ntstatus));
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
}
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate the output buffer for the returned directory name
|
|
//
|
|
*DirEntry = (PVOID) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
DirInfo->FileNameLength + sizeof(WCHAR)
|
|
);
|
|
|
|
if (*DirEntry == NULL) {
|
|
KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry LocalAlloc Failed %lu\n",
|
|
GetLastError()));
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto CleanExit;
|
|
}
|
|
|
|
memcpy(*DirEntry, DirInfo->FileName, DirInfo->FileNameLength);
|
|
|
|
#if DBG
|
|
IF_DEBUG(ENUM) {
|
|
KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry returns %ws\n",
|
|
*DirEntry));
|
|
}
|
|
#endif
|
|
|
|
status = NO_ERROR;
|
|
|
|
CleanExit:
|
|
(void) LocalFree((HLOCAL) DirInfo);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwWriteNetResourceEntry(
|
|
IN OUT LPBYTE * FixedPortion,
|
|
IN OUT LPWSTR * EndOfVariableData,
|
|
IN LPWSTR ContainerName OPTIONAL,
|
|
IN LPWSTR LocalName OPTIONAL,
|
|
IN LPWSTR RemoteName,
|
|
IN DWORD ScopeFlag,
|
|
IN DWORD DisplayFlag,
|
|
IN DWORD UsageFlag,
|
|
IN DWORD ResourceType,
|
|
IN LPWSTR SystemPath OPTIONAL,
|
|
OUT LPWSTR * lppSystem OPTIONAL,
|
|
OUT LPDWORD EntrySize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function packages a NETRESOURCE entry into the user output buffer.
|
|
It is called by the various enum resource routines.
|
|
|
|
Arguments:
|
|
|
|
FixedPortion - Supplies a pointer to the output buffer where the next
|
|
entry of the fixed portion of the use information will be written.
|
|
This pointer is updated to point to the next fixed portion entry
|
|
after a NETRESOURCE entry is written.
|
|
|
|
EndOfVariableData - Supplies a pointer just off the last available byte
|
|
in the output buffer. This is because the variable portion of the
|
|
user information is written into the output buffer starting from
|
|
the end.
|
|
|
|
This pointer is updated after any variable length information is
|
|
written to the output buffer.
|
|
|
|
ContainerName - Supplies the full path qualifier to make RemoteName
|
|
a full UNC name.
|
|
|
|
LocalName - Supplies the local device name, if any.
|
|
|
|
RemoteName - Supplies the remote resource name.
|
|
|
|
ScopeFlag - Supplies the flag which indicates whether this is a
|
|
CONNECTED or GLOBALNET resource.
|
|
|
|
DisplayFlag - Supplies the flag which tells the UI how to display
|
|
the resource.
|
|
|
|
UsageFlag - Supplies the flag which indicates that the RemoteName
|
|
is either a container or a connectable resource or both.
|
|
|
|
SystemPath - Supplies the optional system path data to be stored in the
|
|
NETRESOURCE buffer. This is used by the NPGetResourceInformation
|
|
helper routines.
|
|
|
|
lppSystem - If SystemPath is provided, this will point to the location
|
|
in the NETRESOURCE buffer that contains the system path string.
|
|
|
|
EntrySize - Receives the size of the NETRESOURCE entry in bytes.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - Successfully wrote entry into user buffer.
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - Failed to allocate work buffer.
|
|
|
|
WN_MORE_DATA - Buffer was too small to fit entry.
|
|
|
|
--*/ // NwWriteNetResourceEntry
|
|
{
|
|
BOOL FitInBuffer = TRUE;
|
|
LPNETRESOURCEW NetR = (LPNETRESOURCEW) *FixedPortion;
|
|
LPWSTR RemoteBuffer;
|
|
LPWSTR lpSystem;
|
|
|
|
*EntrySize = sizeof(NETRESOURCEW) +
|
|
(wcslen(RemoteName) + wcslen(NwProviderName) + 2) *
|
|
sizeof(WCHAR);
|
|
|
|
|
|
if (ARGUMENT_PRESENT(LocalName)) {
|
|
*EntrySize += (wcslen(LocalName) + 1) * sizeof(WCHAR);
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(ContainerName)) {
|
|
*EntrySize += wcslen(ContainerName) * sizeof(WCHAR);
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(SystemPath)) {
|
|
*EntrySize += wcslen(SystemPath) * sizeof(WCHAR);
|
|
}
|
|
|
|
*EntrySize = ROUND_UP_COUNT( *EntrySize, ALIGN_DWORD);
|
|
|
|
//
|
|
// See if buffer is large enough to fit the entry.
|
|
//
|
|
if ((LPWSTR) ( *FixedPortion + *EntrySize) > *EndOfVariableData) {
|
|
|
|
return WN_MORE_DATA;
|
|
}
|
|
|
|
NetR->dwScope = ScopeFlag;
|
|
NetR->dwType = ResourceType;
|
|
NetR->dwDisplayType = DisplayFlag;
|
|
NetR->dwUsage = UsageFlag;
|
|
NetR->lpComment = NULL;
|
|
|
|
//
|
|
// Update fixed entry pointer to next entry.
|
|
//
|
|
(*FixedPortion) += sizeof(NETRESOURCEW);
|
|
|
|
//
|
|
// RemoteName
|
|
//
|
|
if (ARGUMENT_PRESENT(ContainerName)) {
|
|
|
|
//
|
|
// Prefix the RemoteName with its container name making the
|
|
// it a fully-qualified UNC name.
|
|
//
|
|
RemoteBuffer = (PVOID) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
(wcslen(RemoteName) + wcslen(ContainerName) + 1) *
|
|
sizeof(WCHAR)
|
|
);
|
|
|
|
if (RemoteBuffer == NULL) {
|
|
KdPrint(("NWWORKSTATION: NwWriteNetResourceEntry LocalAlloc failed %lu\n",
|
|
GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
wcscpy(RemoteBuffer, ContainerName);
|
|
wcscat(RemoteBuffer, RemoteName);
|
|
}
|
|
else {
|
|
RemoteBuffer = RemoteName;
|
|
}
|
|
|
|
FitInBuffer = NwlibCopyStringToBuffer(
|
|
RemoteBuffer,
|
|
wcslen(RemoteBuffer),
|
|
(LPCWSTR) *FixedPortion,
|
|
EndOfVariableData,
|
|
&NetR->lpRemoteName
|
|
);
|
|
|
|
if (ARGUMENT_PRESENT(ContainerName)) {
|
|
(void) LocalFree((HLOCAL) RemoteBuffer);
|
|
}
|
|
|
|
ASSERT(FitInBuffer);
|
|
|
|
//
|
|
// LocalName
|
|
//
|
|
if (ARGUMENT_PRESENT(LocalName)) {
|
|
FitInBuffer = NwlibCopyStringToBuffer(
|
|
LocalName,
|
|
wcslen(LocalName),
|
|
(LPCWSTR) *FixedPortion,
|
|
EndOfVariableData,
|
|
&NetR->lpLocalName
|
|
);
|
|
|
|
ASSERT(FitInBuffer);
|
|
}
|
|
else {
|
|
NetR->lpLocalName = NULL;
|
|
}
|
|
|
|
//
|
|
// SystemPath
|
|
//
|
|
if (ARGUMENT_PRESENT(SystemPath)) {
|
|
FitInBuffer = NwlibCopyStringToBuffer(
|
|
SystemPath,
|
|
wcslen(SystemPath),
|
|
(LPCWSTR) *FixedPortion,
|
|
EndOfVariableData,
|
|
&lpSystem
|
|
);
|
|
|
|
ASSERT(FitInBuffer);
|
|
}
|
|
else {
|
|
lpSystem = NULL;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(lppSystem)) {
|
|
*lppSystem = lpSystem;
|
|
}
|
|
|
|
//
|
|
// ProviderName
|
|
//
|
|
FitInBuffer = NwlibCopyStringToBuffer(
|
|
NwProviderName,
|
|
wcslen(NwProviderName),
|
|
(LPCWSTR) *FixedPortion,
|
|
EndOfVariableData,
|
|
&NetR->lpProvider
|
|
);
|
|
|
|
ASSERT(FitInBuffer);
|
|
|
|
if (! FitInBuffer) {
|
|
return WN_MORE_DATA;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwWritePrinterInfoEntry(
|
|
IN OUT LPBYTE *FixedPortion,
|
|
IN OUT LPWSTR *EndOfVariableData,
|
|
IN LPWSTR ContainerName OPTIONAL,
|
|
IN LPWSTR RemoteName,
|
|
IN DWORD Flags,
|
|
OUT LPDWORD EntrySize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function packages a PRINTER_INFO_1 entry into the user output buffer.
|
|
|
|
Arguments:
|
|
|
|
FixedPortion - Supplies a pointer to the output buffer where the next
|
|
entry of the fixed portion of the use information will be written.
|
|
This pointer is updated to point to the next fixed portion entry
|
|
after a PRINT_INFO_1 entry is written.
|
|
|
|
EndOfVariableData - Supplies a pointer just off the last available byte
|
|
in the output buffer. This is because the variable portion of the
|
|
user information is written into the output buffer starting from
|
|
the end.
|
|
|
|
This pointer is updated after any variable length information is
|
|
written to the output buffer.
|
|
|
|
ContainerName - Supplies the full path qualifier to make RemoteName
|
|
a full UNC name.
|
|
|
|
RemoteName - Supplies the remote resource name.
|
|
|
|
Flags - Supplies the flag which indicates that the RemoteName
|
|
is either a container or not and the icon to use.
|
|
|
|
EntrySize - Receives the size of the PRINTER_INFO_1 entry in bytes.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - Successfully wrote entry into user buffer.
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - Failed to allocate work buffer.
|
|
|
|
ERROR_INSUFFICIENT_BUFFER - Buffer was too small to fit entry.
|
|
|
|
--*/ // NwWritePrinterInfoEntry
|
|
{
|
|
BOOL FitInBuffer = TRUE;
|
|
PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) *FixedPortion;
|
|
LPWSTR RemoteBuffer;
|
|
|
|
*EntrySize = sizeof(PRINTER_INFO_1W) +
|
|
( 2 * wcslen(RemoteName) + 2) * sizeof(WCHAR);
|
|
|
|
if (ARGUMENT_PRESENT(ContainerName)) {
|
|
*EntrySize += wcslen(ContainerName) * sizeof(WCHAR);
|
|
}
|
|
else {
|
|
// 3 is for the length of "!\\"
|
|
*EntrySize += (wcslen(NwProviderName) + 3) * sizeof(WCHAR);
|
|
}
|
|
|
|
*EntrySize = ROUND_UP_COUNT( *EntrySize, ALIGN_DWORD);
|
|
|
|
//
|
|
// See if buffer is large enough to fit the entry.
|
|
//
|
|
if ((LPWSTR) (*FixedPortion + *EntrySize) > *EndOfVariableData) {
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
pPrinterInfo1->Flags = Flags;
|
|
pPrinterInfo1->pComment = NULL;
|
|
|
|
//
|
|
// Update fixed entry pointer to next entry.
|
|
//
|
|
(*FixedPortion) += sizeof(PRINTER_INFO_1W);
|
|
|
|
//
|
|
// Name
|
|
//
|
|
if (ARGUMENT_PRESENT(ContainerName)) {
|
|
|
|
//
|
|
// Prefix the RemoteName with its container name making the
|
|
// it a fully-qualified UNC name.
|
|
//
|
|
RemoteBuffer = (PVOID) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
(wcslen(ContainerName) + wcslen(RemoteName)
|
|
+ 1) * sizeof(WCHAR) );
|
|
|
|
if (RemoteBuffer == NULL) {
|
|
KdPrint(("NWWORKSTATION: NwWritePrinterInfoEntry LocalAlloc failed %lu\n", GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
wcscpy(RemoteBuffer, ContainerName);
|
|
wcscat(RemoteBuffer, RemoteName);
|
|
}
|
|
else {
|
|
//
|
|
// Prefix the RemoteName with its provider name
|
|
//
|
|
RemoteBuffer = (PVOID) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
(wcslen(RemoteName) +
|
|
wcslen(NwProviderName) + 4)
|
|
* sizeof(WCHAR) );
|
|
|
|
if (RemoteBuffer == NULL) {
|
|
KdPrint(("NWWORKSTATION: NwWritePrinterInfoEntry LocalAlloc failed %lu\n", GetLastError()));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
wcscpy(RemoteBuffer, NwProviderName );
|
|
wcscat(RemoteBuffer, L"!\\\\" );
|
|
wcscat(RemoteBuffer, RemoteName);
|
|
}
|
|
|
|
FitInBuffer = NwlibCopyStringToBuffer(
|
|
RemoteBuffer,
|
|
wcslen(RemoteBuffer),
|
|
(LPCWSTR) *FixedPortion,
|
|
EndOfVariableData,
|
|
&pPrinterInfo1->pName );
|
|
|
|
(void) LocalFree((HLOCAL) RemoteBuffer);
|
|
|
|
ASSERT(FitInBuffer);
|
|
|
|
//
|
|
// Description
|
|
//
|
|
FitInBuffer = NwlibCopyStringToBuffer(
|
|
RemoteName,
|
|
wcslen(RemoteName),
|
|
(LPCWSTR) *FixedPortion,
|
|
EndOfVariableData,
|
|
&pPrinterInfo1->pDescription );
|
|
|
|
ASSERT(FitInBuffer);
|
|
|
|
if (! FitInBuffer) {
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
int __cdecl
|
|
SortFunc(
|
|
IN CONST VOID *p1,
|
|
IN CONST VOID *p2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used in qsort to compare the descriptions of
|
|
two printer_info_1 structure.
|
|
|
|
Arguments:
|
|
|
|
p1 - Points to a PRINTER_INFO_1 structure
|
|
p2 - Points to a PRINTER_INFO_1 structure to compare with p1
|
|
|
|
Return Value:
|
|
|
|
Same as return value of lstrccmpi.
|
|
|
|
--*/
|
|
{
|
|
PRINTER_INFO_1W *pFirst = (PRINTER_INFO_1W *) p1;
|
|
PRINTER_INFO_1W *pSecond = (PRINTER_INFO_1W *) p2;
|
|
|
|
return lstrcmpiW( pFirst->pDescription, pSecond->pDescription );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NwGetConnectionInformation(
|
|
IN LPWSTR lpName,
|
|
OUT LPWSTR lpUserName,
|
|
OUT LPWSTR lpHostServer
|
|
)
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
NTSTATUS ntstatus = STATUS_SUCCESS;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
ACCESS_MASK DesiredAccess = SYNCHRONIZE | FILE_LIST_DIRECTORY;
|
|
HANDLE hRdr = NULL;
|
|
BOOL fImpersonate = FALSE ;
|
|
|
|
WCHAR OpenString[] = L"\\Device\\Nwrdr\\*";
|
|
UNICODE_STRING OpenName;
|
|
|
|
OEM_STRING OemArg;
|
|
UNICODE_STRING ConnectionName;
|
|
WCHAR ConnectionBuffer[512];
|
|
|
|
ULONG BufferSize = 512;
|
|
ULONG RequestSize, ReplyLen;
|
|
PNWR_REQUEST_PACKET Request;
|
|
BYTE *Reply;
|
|
|
|
PCONN_INFORMATION pConnInfo;
|
|
UNICODE_STRING Name;
|
|
|
|
//
|
|
// Allocate buffer space.
|
|
//
|
|
|
|
Request = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT, BufferSize );
|
|
|
|
if ( !Request )
|
|
{
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Impersonate the client
|
|
//
|
|
if ( ( status = NwImpersonateClient() ) != NO_ERROR )
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
fImpersonate = TRUE;
|
|
|
|
//
|
|
// Convert the connect name to unicode.
|
|
//
|
|
ConnectionName.Length = wcslen( lpName )* sizeof(WCHAR);
|
|
ConnectionName.MaximumLength = sizeof( ConnectionBuffer );
|
|
ConnectionName.Buffer = ConnectionBuffer;
|
|
|
|
if (ConnectionName.Length > MAX_NDS_NAME_SIZE)
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wcscpy( ConnectionName.Buffer, lpName );
|
|
_wcsupr( ConnectionName.Buffer );
|
|
|
|
//
|
|
// Set up the object attributes.
|
|
//
|
|
|
|
RtlInitUnicodeString( &OpenName, OpenString );
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&OpenName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
ntstatus = NtOpenFile( &hRdr,
|
|
DesiredAccess,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_VALID_FLAGS,
|
|
FILE_SYNCHRONOUS_IO_NONALERT );
|
|
|
|
if ( ntstatus != STATUS_SUCCESS )
|
|
{
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Fill out the request packet for FSCTL_NWR_GET_CONN_INFO.
|
|
//
|
|
|
|
Request->Parameters.GetConnInfo.ConnectionNameLength = ConnectionName.Length;
|
|
RtlCopyMemory( &(Request->Parameters.GetConnInfo.ConnectionName[0]),
|
|
ConnectionBuffer,
|
|
ConnectionName.Length );
|
|
|
|
RequestSize = sizeof( Request->Parameters.GetConnInfo ) + ConnectionName.Length;
|
|
Reply = ((PBYTE)Request) + RequestSize;
|
|
ReplyLen = BufferSize - RequestSize;
|
|
|
|
ntstatus = NtFsControlFile( hRdr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
FSCTL_NWR_GET_CONN_INFO,
|
|
(PVOID) Request,
|
|
RequestSize,
|
|
(PVOID) Reply,
|
|
ReplyLen );
|
|
|
|
if ( ntstatus != STATUS_SUCCESS )
|
|
{
|
|
status = RtlNtStatusToDosError(ntstatus);
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
(void) NwRevertToSelf() ;
|
|
fImpersonate = FALSE;
|
|
|
|
NtClose( hRdr );
|
|
|
|
pConnInfo = (PCONN_INFORMATION) Reply;
|
|
wcscpy( lpUserName, pConnInfo->UserName );
|
|
wcscpy( lpHostServer, pConnInfo->HostServer );
|
|
|
|
LocalFree( Request );
|
|
|
|
return NO_ERROR;
|
|
|
|
ErrorExit:
|
|
|
|
if ( fImpersonate )
|
|
(void) NwRevertToSelf() ;
|
|
|
|
if ( Request )
|
|
LocalFree( Request );
|
|
|
|
if ( hRdr )
|
|
NtClose( hRdr );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NwpGetUncInfo(
|
|
IN LPWSTR lpstrUnc,
|
|
OUT WORD * slashCount,
|
|
OUT BOOL * isNdsUnc,
|
|
OUT LPWSTR * FourthSlash
|
|
)
|
|
{
|
|
WORD i;
|
|
WORD length = (WORD) wcslen( lpstrUnc );
|
|
|
|
*isNdsUnc = (BOOL) FALSE;
|
|
*slashCount = 0;
|
|
*FourthSlash = NULL;
|
|
|
|
for ( i = 0; i < length; i++ )
|
|
{
|
|
if ( lpstrUnc[i] == L'=' )
|
|
{
|
|
*isNdsUnc = TRUE;
|
|
}
|
|
|
|
if ( lpstrUnc[i] == L'\\' )
|
|
{
|
|
*slashCount += 1;
|
|
|
|
if ( *slashCount == 4 )
|
|
{
|
|
*FourthSlash = &lpstrUnc[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwpGetCurrentUserRegKey(
|
|
IN DWORD DesiredAccess,
|
|
OUT HKEY *phKeyCurrentUser
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens the current user's registry key under
|
|
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NWCWorkstation\Parameters
|
|
|
|
Arguments:
|
|
|
|
DesiredAccess - The access mask to open the key with
|
|
|
|
phKeyCurrentUser - Receives the opened key handle
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD err;
|
|
HKEY hkeyWksta;
|
|
LPWSTR CurrentUser;
|
|
|
|
HKEY hInteractiveLogonKey; //Multi-user
|
|
HKEY OneLogonKey; //Multi-user
|
|
LUID logonid; //Multi-user
|
|
WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN]; //Multi-user
|
|
|
|
//
|
|
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
|
// \NWCWorkstation\Parameters
|
|
//
|
|
err = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
NW_WORKSTATION_REGKEY,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ,
|
|
&hkeyWksta
|
|
);
|
|
|
|
if ( err ) {
|
|
KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Parameters key unexpected error %lu!\n", err));
|
|
return err;
|
|
}
|
|
|
|
|
|
//
|
|
// Impersonate the client
|
|
//
|
|
if ( ( err = NwImpersonateClient() ) != NO_ERROR ) {
|
|
(void) RegCloseKey( hkeyWksta );
|
|
return err;
|
|
}
|
|
|
|
//
|
|
// Get the NT logon id
|
|
//
|
|
GetLuid( &logonid );
|
|
|
|
//
|
|
// Revert
|
|
//
|
|
(void) NwRevertToSelf() ;
|
|
|
|
// Open interactive user section
|
|
|
|
err = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
NW_INTERACTIVE_LOGON_REGKEY,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ,
|
|
&hInteractiveLogonKey
|
|
);
|
|
|
|
if ( err ) {
|
|
KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Interactive logon key unexpected error %lu!\n", err));
|
|
(void) RegCloseKey( hkeyWksta );
|
|
return err;
|
|
}
|
|
|
|
// Open the logonid
|
|
|
|
NwLuidToWStr(&logonid, LogonIdKeyName);
|
|
|
|
err = RegOpenKeyExW(
|
|
hInteractiveLogonKey,
|
|
LogonIdKeyName,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ,
|
|
&OneLogonKey
|
|
);
|
|
|
|
(void) RegCloseKey( hInteractiveLogonKey );
|
|
|
|
if ( err ) {
|
|
KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open logon key unexpected error %lu!\n", err));
|
|
(void) RegCloseKey( hkeyWksta );
|
|
return err;
|
|
}
|
|
|
|
// Read SID
|
|
|
|
err = NwReadRegValue(
|
|
OneLogonKey,
|
|
NW_SID_VALUENAME,
|
|
&CurrentUser
|
|
);
|
|
|
|
(void) RegCloseKey( OneLogonKey );
|
|
(void) RegCloseKey( hkeyWksta );
|
|
|
|
if ( err ) {
|
|
KdPrint(("NWPROVAU: NwGetCurrentUserRegKey read user Sid unexpected error %lu!\n", err));
|
|
return err;
|
|
}
|
|
|
|
//
|
|
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
|
// \NWCWorkstation\Parameters\Option
|
|
//
|
|
err = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
NW_WORKSTATION_OPTION_REGKEY,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ,
|
|
&hkeyWksta
|
|
);
|
|
|
|
if ( err ) {
|
|
KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Parameters\\Option key unexpected error %lu!\n", err));
|
|
return err;
|
|
}
|
|
|
|
//
|
|
// Open current user's key
|
|
//
|
|
err = RegOpenKeyExW(
|
|
hkeyWksta,
|
|
CurrentUser,
|
|
REG_OPTION_NON_VOLATILE,
|
|
DesiredAccess,
|
|
phKeyCurrentUser
|
|
);
|
|
|
|
if ( err == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
DWORD Disposition;
|
|
|
|
//
|
|
// Create <NewUser> key under NWCWorkstation\Parameters\Option
|
|
//
|
|
err = RegCreateKeyExW(
|
|
hkeyWksta,
|
|
CurrentUser,
|
|
0,
|
|
WIN31_CLASS,
|
|
REG_OPTION_NON_VOLATILE,
|
|
DesiredAccess,
|
|
NULL, // security attr
|
|
phKeyCurrentUser,
|
|
&Disposition
|
|
);
|
|
|
|
}
|
|
|
|
if ( err ) {
|
|
KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open or create of Parameters\\Option\\%ws key failed %lu\n", CurrentUser, err));
|
|
}
|
|
|
|
(void) RegCloseKey( hkeyWksta );
|
|
(void) LocalFree((HLOCAL)CurrentUser) ;
|
|
return err;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwQueryInfo(
|
|
OUT LPWSTR *ppszPreferredSrv
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine gets the user's preferred server and print options from
|
|
the registry.
|
|
|
|
Arguments:
|
|
|
|
ppszPreferredSrv - Receives the user's preferred server
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
|
|
HKEY hKeyCurrentUser = NULL;
|
|
DWORD BufferSize;
|
|
DWORD BytesNeeded;
|
|
DWORD ValueType;
|
|
LPWSTR PreferredServer ;
|
|
DWORD err ;
|
|
|
|
//
|
|
// get to right place in registry and allocate dthe buffer
|
|
//
|
|
if (err = NwpGetCurrentUserRegKey( KEY_READ, &hKeyCurrentUser))
|
|
{
|
|
//
|
|
// If somebody mess around with the registry and we can't find
|
|
// the registry, just use the defaults.
|
|
//
|
|
*ppszPreferredSrv = NULL;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
BufferSize = sizeof(WCHAR) * (MAX_PATH + 2) ;
|
|
PreferredServer = (LPWSTR) LocalAlloc(LPTR, BufferSize) ;
|
|
if (!PreferredServer)
|
|
return (GetLastError()) ;
|
|
|
|
//
|
|
// Read PreferredServer value into Buffer.
|
|
//
|
|
BytesNeeded = BufferSize ;
|
|
|
|
err = RegQueryValueExW( hKeyCurrentUser,
|
|
NW_SERVER_VALUENAME,
|
|
NULL,
|
|
&ValueType,
|
|
(LPBYTE) PreferredServer,
|
|
&BytesNeeded );
|
|
|
|
if (err != NO_ERROR)
|
|
{
|
|
//
|
|
// set to empty and carry on
|
|
//
|
|
PreferredServer[0] = 0;
|
|
}
|
|
|
|
if (hKeyCurrentUser != NULL)
|
|
(void) RegCloseKey(hKeyCurrentUser) ;
|
|
*ppszPreferredSrv = PreferredServer ;
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
|