summaryrefslogtreecommitdiffstats
path: root/private/nw/svcdlls/nwwks/client/nwutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/svcdlls/nwwks/client/nwutil.c')
-rw-r--r--private/nw/svcdlls/nwwks/client/nwutil.c872
1 files changed, 872 insertions, 0 deletions
diff --git a/private/nw/svcdlls/nwwks/client/nwutil.c b/private/nw/svcdlls/nwwks/client/nwutil.c
new file mode 100644
index 000000000..f39a0de0d
--- /dev/null
+++ b/private/nw/svcdlls/nwwks/client/nwutil.c
@@ -0,0 +1,872 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ nwutil.c
+
+Abstract:
+
+ Contains some misc functions used by shell extensions
+
+Author:
+
+ Yi-Hsin Sung (yihsins) 25-Oct-1995
+
+Environment:
+
+ User Mode - Win32
+
+Revision History:
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntddnwfs.h>
+#include <ndsapi32.h>
+#include <nwmisc.h>
+#include "nwclient.h"
+#include "nwapi.h"
+#include "nwutil.h"
+
+#define EXTRA_BYTES 256
+
+BOOL
+NwIsNdsSyntax(
+ IN LPWSTR lpstrUnc
+)
+{
+ HANDLE hTreeConn;
+ DWORD dwOid;
+ DWORD status = NO_ERROR;
+
+ if ( lpstrUnc == NULL )
+ return FALSE;
+
+ status = NwOpenAndGetTreeInfo( lpstrUnc, &hTreeConn, &dwOid );
+
+ if ( status != NO_ERROR )
+ {
+ return FALSE;
+ }
+
+ CloseHandle( hTreeConn );
+
+ return TRUE;
+}
+
+VOID
+NwAbbreviateUserName(
+ IN LPWSTR pszFullName,
+ OUT LPWSTR pszUserName
+)
+{
+ if ( pszUserName == NULL )
+ return;
+
+ if ( NwIsNdsSyntax( pszFullName ))
+ {
+ //
+ // BUGBUG - This part of the code never gets called due to the
+ // change in how NwIsNdsSyntax works. Post NT 4.0, get rid of the
+ // NwIsNdsSyntax test and run this section of code no matter what.
+ // This bug was not fixed in NT4.0 due to the extremely close time
+ // to the ship date.
+ //
+ LPWSTR pszTemp = pszFullName;
+ LPWSTR pszLast = pszTemp;
+
+ *pszUserName = 0;
+
+ while ( pszTemp = wcschr( pszTemp, L'='))
+ {
+ WCHAR NextChar;
+
+ NextChar = *(++pszTemp);
+
+ while ( NextChar != 0 && NextChar != L'.' )
+ {
+ *(pszUserName++) = *pszTemp;
+ NextChar = *(++pszTemp);
+ }
+
+ if ( NextChar == 0 )
+ {
+ pszLast = NULL;
+ break;
+ }
+
+ *(pszUserName++) = *pszTemp; // put back the '.'
+ pszLast = ++pszTemp;
+ }
+
+ if ( pszLast != NULL )
+ {
+ while ( *pszLast != 0 )
+ *(pszUserName++) = *(pszLast++);
+ }
+
+ *pszUserName = 0;
+ }
+ else
+ {
+ wcscpy( pszUserName, pszFullName );
+ }
+}
+
+VOID
+NwMakePrettyDisplayName(
+ IN LPWSTR pszName
+)
+{
+ if ( pszName )
+ {
+ CharLower( pszName );
+ CharUpperBuff( pszName, 1);
+ }
+}
+
+VOID
+NwExtractTreeName(
+ IN LPWSTR pszUNCPath,
+ OUT LPWSTR pszTreeName
+)
+{
+ LPWSTR pszTemp = NULL;
+
+ if ( pszTreeName == NULL )
+ return;
+
+ pszTreeName[0] = 0;
+
+ if ( pszUNCPath == NULL )
+ return;
+
+ if ( pszUNCPath[0] == L' ')
+ pszUNCPath++;
+
+ if ( ( pszUNCPath[0] != L'\\')
+ || ( pszUNCPath[1] != L'\\')
+ )
+ {
+ return;
+ }
+
+ wcscpy( pszTreeName, pszUNCPath + 2 ); // get past "\\"
+
+ if ( pszTemp = wcschr( pszTreeName, L'\\' ))
+ *pszTemp = 0;
+}
+
+VOID
+NwExtractServerName(
+ IN LPWSTR pszUNCPath,
+ OUT LPWSTR pszServerName
+)
+{
+ LPWSTR pszTemp = NULL;
+
+ if ( pszServerName == NULL )
+ return;
+
+ pszServerName[0] = 0;
+
+ if ( ( pszUNCPath == NULL )
+ || ( pszUNCPath[0] != L'\\')
+ || ( pszUNCPath[1] != L'\\')
+ )
+ {
+ return;
+ }
+
+ if ( NwIsNdsSyntax( pszUNCPath ))
+ {
+ pszTemp = wcschr( pszUNCPath + 2, L'\\' ); // get past "\\"
+ wcscpy( pszServerName, pszTemp + 1 ); // get past "\"
+
+ if ( pszTemp = wcschr( pszServerName, L'.' ))
+ *pszTemp = 0;
+
+ }
+ else
+ {
+ wcscpy( pszServerName, pszUNCPath + 2 ); // get past "\\"
+
+ if ( pszTemp = wcschr( pszServerName, L'\\' ))
+ *pszTemp = 0;
+ }
+}
+
+VOID
+NwExtractShareName(
+ IN LPWSTR pszUNCPath,
+ OUT LPWSTR pszShareName
+)
+{
+ LPWSTR pszTemp = NULL;
+
+ if ( pszShareName == NULL )
+ return;
+
+ pszShareName[0] = 0;
+
+ if ( ( pszUNCPath == NULL )
+ || ( pszUNCPath[0] != L'\\')
+ || ( pszUNCPath[1] != L'\\')
+ )
+ {
+ return;
+ }
+
+ if ( NwIsNdsSyntax( pszUNCPath ))
+ {
+ pszTemp = wcschr( pszUNCPath + 2, L'\\' ); // get past "\\"
+ wcscpy( pszShareName, pszTemp + 1 ); // get past "\"
+
+ if ( pszTemp = wcschr( pszShareName, L'.' ))
+ *pszTemp = 0;
+ }
+ else
+ {
+ pszTemp = wcschr( pszUNCPath + 2, L'\\' ); // get past "\\"
+ wcscpy( pszShareName, pszTemp + 1); // get past "\"
+
+ if ( pszTemp = wcschr( pszShareName, L'\\' ))
+ *pszTemp = 0;
+ }
+}
+
+DWORD
+NwIsServerInDefaultTree(
+ IN LPWSTR pszFullServerName,
+ OUT BOOL *pfInDefaultTree
+)
+{
+ DWORD err = NO_ERROR;
+ LPWSTR pszCurrentContext = NULL;
+ DWORD dwPrintOptions;
+ WCHAR szTreeName[MAX_PATH + 1];
+
+ *pfInDefaultTree = FALSE;
+
+ if ( !NwIsNdsSyntax( pszFullServerName ))
+ {
+ // The full server name does not contain any NDS information
+ // In this case, assume the server is not in the tree.
+ // If a server belongs the default tree, we would get the full
+ // NDS information.
+ return NO_ERROR;
+ }
+
+ // Get the current default tree or server name
+ err = NwQueryInfo( &dwPrintOptions, &pszCurrentContext );
+
+ if ( (err == NO_ERROR) && ( *pszCurrentContext == TREECHAR))
+ {
+ // Yes, there is a default tree.
+ // So, get the tree name out of *TREE\CONTEXT
+ LPWSTR pszTemp = wcschr( pszCurrentContext, L'\\');
+ if ( pszTemp )
+ *pszTemp = 0;
+
+ // Need to extract the tree name from full UNC path
+ NwExtractTreeName( pszFullServerName, szTreeName );
+
+ if ( _wcsicmp( szTreeName,
+ pszCurrentContext + 1) == 0 ) // get past the tree char
+ {
+ *pfInDefaultTree = TRUE;
+ }
+ }
+
+ if ( pszCurrentContext != NULL )
+ LocalFree( pszCurrentContext );
+
+ return err;
+}
+
+DWORD
+NwIsServerOrTreeAttached(
+ IN LPWSTR pszName,
+ OUT BOOL *pfAttached,
+ OUT BOOL *pfAuthenticated
+)
+{
+ DWORD err = NO_ERROR;
+ DWORD EntriesRead = 0;
+ DWORD ResumeKey = 0;
+ LPBYTE Buffer = NULL;
+
+ err = NwGetConnectionStatus(
+ pszName,
+ &ResumeKey,
+ &Buffer,
+ &EntriesRead );
+
+ *pfAttached = FALSE;
+ *pfAuthenticated = FALSE;
+
+ if (( err == NO_ERROR ) && ( EntriesRead > 0 ))
+ {
+ // For trees, we might get more than one entries back.
+
+ PCONN_STATUS pConnStatus = (PCONN_STATUS) Buffer;
+
+ if ( !pConnStatus->fPreferred )
+ {
+ // We only need to return as attached if this is not a preferred
+ // server implicit connection since we don't want the user to know
+ // about this connection ( which rdr does not allow user to delete)
+
+ *pfAttached = TRUE;
+ *pfAuthenticated = (pConnStatus->dwConnType != NW_CONN_NOT_AUTHENTICATED);
+ }
+ }
+
+ if ( Buffer != NULL )
+ {
+ LocalFree( Buffer );
+ Buffer = NULL;
+ }
+
+ return err;
+}
+
+DWORD
+NwGetConnectionInformation(
+ IN LPWSTR pszName,
+ OUT LPBYTE Buffer,
+ IN DWORD BufferSize
+)
+{
+ NTSTATUS ntstatus = STATUS_SUCCESS;
+ HANDLE handleRdr = NULL;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ UNICODE_STRING uRdrName;
+ WCHAR RdrPrefix[] = L"\\Device\\NwRdr\\*";
+
+ PNWR_REQUEST_PACKET RequestPacket = NULL;
+ DWORD RequestPacketSize = 0;
+ DWORD dwNameLen = 0;
+
+ if ( pszName == NULL )
+ return ERROR_INVALID_PARAMETER;
+
+ //
+ // Set up the object attributes.
+ //
+
+ RtlInitUnicodeString( &uRdrName, RdrPrefix );
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &uRdrName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ ntstatus = NtOpenFile( &handleRdr,
+ SYNCHRONIZE | FILE_LIST_DIRECTORY,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT );
+
+ if ( !NT_SUCCESS(ntstatus) )
+ goto CleanExit;
+
+ dwNameLen = wcslen(pszName) * sizeof(WCHAR);
+
+ RequestPacketSize = sizeof( NWR_REQUEST_PACKET ) + dwNameLen;
+
+ RequestPacket = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT,
+ RequestPacketSize );
+
+ if ( RequestPacket == NULL )
+ {
+ ntstatus = STATUS_NO_MEMORY;
+ goto CleanExit;
+ }
+
+ //
+ // Fill out the request packet for FSCTL_NWR_GET_CONN_INFO.
+ //
+
+ RequestPacket->Version = REQUEST_PACKET_VERSION;
+ RequestPacket->Parameters.GetConnInfo.ConnectionNameLength = dwNameLen;
+
+ RtlCopyMemory( &(RequestPacket->Parameters.GetConnInfo.ConnectionName[0]),
+ pszName,
+ dwNameLen );
+
+ ntstatus = NtFsControlFile( handleRdr,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_GET_CONN_INFO,
+ (PVOID) RequestPacket,
+ RequestPacketSize,
+ (PVOID) Buffer,
+ BufferSize );
+
+ if ( NT_SUCCESS( ntstatus ))
+ ntstatus = IoStatusBlock.Status;
+
+CleanExit:
+
+ if ( handleRdr != NULL )
+ NtClose( handleRdr );
+
+ if ( RequestPacket != NULL )
+ LocalFree( RequestPacket );
+
+ return RtlNtStatusToDosError( ntstatus );
+}
+
+DWORD
+NWPGetConnectionStatus(
+ IN LPWSTR pszRemoteName,
+ IN OUT PDWORD ResumeKey,
+ OUT LPBYTE Buffer,
+ IN DWORD BufferSize,
+ OUT PDWORD BytesNeeded,
+ OUT PDWORD EntriesRead
+)
+{
+ NTSTATUS ntstatus = STATUS_SUCCESS;
+ HANDLE handleRdr = NULL;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ UNICODE_STRING uRdrName;
+ WCHAR RdrPrefix[] = L"\\Device\\NwRdr\\*";
+
+ PNWR_REQUEST_PACKET RequestPacket = NULL;
+ DWORD RequestPacketSize = 0;
+ DWORD dwRemoteNameLen = 0;
+
+ //
+ // Set up the object attributes.
+ //
+
+ RtlInitUnicodeString( &uRdrName, RdrPrefix );
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &uRdrName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ ntstatus = NtOpenFile( &handleRdr,
+ SYNCHRONIZE | FILE_LIST_DIRECTORY,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT );
+
+ if ( !NT_SUCCESS(ntstatus) )
+ goto CleanExit;
+
+ dwRemoteNameLen = pszRemoteName? wcslen(pszRemoteName)*sizeof(WCHAR) : 0;
+
+ RequestPacketSize = sizeof( NWR_REQUEST_PACKET ) + dwRemoteNameLen;
+
+ RequestPacket = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT,
+ RequestPacketSize );
+
+ if ( RequestPacket == NULL )
+ {
+ ntstatus = STATUS_NO_MEMORY;
+ goto CleanExit;
+ }
+
+ //
+ // Fill out the request packet for FSCTL_NWR_GET_CONN_STATUS.
+ //
+
+ RequestPacket->Parameters.GetConnStatus.ResumeKey = *ResumeKey;
+
+ RequestPacket->Version = REQUEST_PACKET_VERSION;
+ RequestPacket->Parameters.GetConnStatus.ConnectionNameLength = dwRemoteNameLen;
+
+ RtlCopyMemory( &(RequestPacket->Parameters.GetConnStatus.ConnectionName[0]),
+ pszRemoteName,
+ dwRemoteNameLen );
+
+ ntstatus = NtFsControlFile( handleRdr,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_GET_CONN_STATUS,
+ (PVOID) RequestPacket,
+ RequestPacketSize,
+ (PVOID) Buffer,
+ BufferSize );
+
+ if ( NT_SUCCESS( ntstatus ))
+ ntstatus = IoStatusBlock.Status;
+
+ *EntriesRead = RequestPacket->Parameters.GetConnStatus.EntriesReturned;
+ *ResumeKey = RequestPacket->Parameters.GetConnStatus.ResumeKey;
+ *BytesNeeded = RequestPacket->Parameters.GetConnStatus.BytesNeeded;
+
+CleanExit:
+
+ if ( handleRdr != NULL )
+ NtClose( handleRdr );
+
+ if ( RequestPacket != NULL )
+ LocalFree( RequestPacket );
+
+ return RtlNtStatusToDosError( ntstatus );
+}
+
+
+DWORD
+NwGetConnectionStatus(
+ IN LPWSTR pszRemoteName,
+ OUT PDWORD ResumeKey,
+ OUT LPBYTE *Buffer,
+ OUT PDWORD EntriesRead
+)
+{
+ DWORD err = NO_ERROR;
+ DWORD dwBytesNeeded = 0;
+ DWORD dwBufferSize = TWO_KB;
+
+ *Buffer = NULL;
+ *EntriesRead = 0;
+
+ do {
+
+ *Buffer = (LPBYTE) LocalAlloc( LMEM_ZEROINIT, dwBufferSize );
+
+ if ( *Buffer == NULL )
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ err = NWPGetConnectionStatus( pszRemoteName,
+ ResumeKey,
+ *Buffer,
+ dwBufferSize,
+ &dwBytesNeeded,
+ EntriesRead );
+
+ if ( err == ERROR_INSUFFICIENT_BUFFER )
+ {
+ dwBufferSize = dwBytesNeeded + EXTRA_BYTES;
+ LocalFree( *Buffer );
+ *Buffer = NULL;
+ }
+
+ } while ( err == ERROR_INSUFFICIENT_BUFFER );
+
+ if ( err == ERROR_INVALID_PARAMETER ) // not attached
+ {
+ err = NO_ERROR;
+ *EntriesRead = 0;
+ }
+
+ return err;
+}
+
+DWORD
+NwGetNdsVolumeInfo(
+ IN LPWSTR pszName,
+ OUT LPWSTR pszServerBuffer,
+ IN WORD wServerBufferSize, // in bytes
+ OUT LPWSTR pszVolumeBuffer,
+ IN WORD wVolumeBufferSize // in bytes
+)
+{
+ NTSTATUS ntstatus = STATUS_SUCCESS;
+ HANDLE handleNdsTree;
+
+ LPWSTR pszTree, pszVolume, pszTemp;
+ UNICODE_STRING uTree, uVolume;
+
+ UNICODE_STRING uHostServer, uHostVolume;
+ WCHAR HostVolumeBuffer[256];
+
+ pszTree = pszName + 2; // get past two backslashes
+
+ pszTemp = wcschr( pszTree, L'\\' );
+ if ( pszTemp )
+ *pszTemp = 0;
+ else
+ return ERROR_INVALID_PARAMETER;
+
+ pszVolume = pszTemp + 1;
+
+ RtlInitUnicodeString( &uTree, pszTree );
+ RtlInitUnicodeString( &uVolume, pszVolume );
+
+ //
+ // Open up a handle to the tree.
+ //
+
+ ntstatus = NwNdsOpenTreeHandle( &uTree,
+ &handleNdsTree );
+
+ if ( !NT_SUCCESS( ntstatus ))
+ goto CleanExit;
+
+ //
+ // Set up the reply strings.
+ //
+
+ uHostServer.Length = 0;
+ uHostServer.MaximumLength = wServerBufferSize;
+ uHostServer.Buffer = pszServerBuffer;
+
+ RtlZeroMemory( pszServerBuffer, wServerBufferSize );
+
+ if ( pszVolumeBuffer != NULL )
+ {
+ uHostVolume.Length = 0;
+ uHostVolume.MaximumLength = wVolumeBufferSize;
+ uHostVolume.Buffer = pszVolumeBuffer;
+
+ RtlZeroMemory( pszVolumeBuffer, wVolumeBufferSize );
+ }
+ else
+ {
+ uHostVolume.Length = 0;
+ uHostVolume.MaximumLength = sizeof( HostVolumeBuffer );
+ uHostVolume.Buffer = HostVolumeBuffer;
+ }
+
+ ntstatus = NwNdsGetVolumeInformation( handleNdsTree,
+ &uVolume,
+ &uHostServer,
+ &uHostVolume );
+
+ CloseHandle( handleNdsTree );
+
+CleanExit:
+
+ if ( pszTemp )
+ *pszTemp = L'\\';
+
+ return RtlNtStatusToDosError( ntstatus );
+}
+
+DWORD
+NwOpenAndGetTreeInfo(
+ LPWSTR pszNdsUNCPath,
+ HANDLE *phTreeConn,
+ DWORD *pdwOid
+)
+{
+ NTSTATUS ntstatus = STATUS_SUCCESS;
+ WCHAR lpServerName[NW_MAX_SERVER_LEN];
+ UNICODE_STRING ServerName;
+
+ UNICODE_STRING ObjectName;
+
+ *phTreeConn = NULL;
+
+ ServerName.Length = 0;
+ ServerName.MaximumLength = sizeof( lpServerName );
+ ServerName.Buffer = lpServerName;
+
+ ObjectName.Buffer = NULL;
+ ObjectName.MaximumLength = ( wcslen( pszNdsUNCPath) + 1 ) * sizeof( WCHAR );
+
+ ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer,
+ pszNdsUNCPath,
+ PARSE_NDS_GET_TREE_NAME );
+
+ if ( ObjectName.Length == 0 || ObjectName.Buffer == NULL )
+ {
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+ //
+ // Open a NDS tree connection handle to \\treename
+ //
+ ntstatus = NwNdsOpenTreeHandle( &ObjectName, phTreeConn );
+
+ if ( !NT_SUCCESS( ntstatus ))
+ {
+ return RtlNtStatusToDosError( ntstatus );
+ }
+
+ //
+ // Get the path to the container to open.
+ //
+ ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer,
+ pszNdsUNCPath,
+ 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.
+ //
+ ntstatus = NwNdsResolveName( *phTreeConn,
+ &Root,
+ pdwOid,
+ &ServerName,
+ NULL,
+ 0 );
+
+ }
+ else
+ {
+ //
+ // Resolve the path to get a NDS object id.
+ //
+ ntstatus = NwNdsResolveName( *phTreeConn,
+ &ObjectName,
+ pdwOid,
+ &ServerName,
+ NULL,
+ 0 );
+
+ }
+
+ if ( ntstatus == STATUS_SUCCESS && ServerName.Length )
+ {
+ DWORD dwHandleType;
+
+ //
+ // NwNdsResolveName succeeded, but we were referred to
+ // another server, though pdwOid is still valid.
+
+ if ( *phTreeConn )
+ CloseHandle( *phTreeConn );
+
+ *phTreeConn = NULL;
+
+ //
+ // Open a NDS generic connection handle to \\ServerName
+ //
+ ntstatus = NwNdsOpenGenericHandle( &ServerName,
+ &dwHandleType,
+ phTreeConn );
+
+ if ( ntstatus != STATUS_SUCCESS )
+ {
+ return RtlNtStatusToDosError(ntstatus);
+ }
+
+ ASSERT( dwHandleType != HANDLE_TYPE_NCP_SERVER );
+ }
+
+ if ( !NT_SUCCESS( ntstatus ))
+ {
+
+ if ( *phTreeConn != NULL )
+ {
+ CloseHandle( *phTreeConn );
+ *phTreeConn = NULL;
+ }
+ return RtlNtStatusToDosError(ntstatus);
+ }
+
+ return NO_ERROR;
+
+}
+
+DWORD
+NwGetConnectedTrees(
+ IN LPWSTR pszNtUserName,
+ OUT LPBYTE Buffer,
+ IN DWORD BufferSize,
+ OUT LPDWORD lpEntriesRead,
+ OUT LPDWORD lpUserLUID
+)
+{
+ NTSTATUS ntstatus = STATUS_SUCCESS;
+ HANDLE handleRdr = NULL;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ WCHAR RdrPrefix[] = L"\\Device\\NwRdr\\*";
+ UNICODE_STRING uRdrName;
+ UNICODE_STRING uNtUserName;
+
+ PNWR_NDS_REQUEST_PACKET Request = NULL;
+ BYTE RequestBuffer[2048];
+ DWORD RequestSize = 0;
+
+ *lpEntriesRead = 0;
+
+ //
+ // Convert the user name to unicode.
+ //
+
+ RtlInitUnicodeString( &uNtUserName, pszNtUserName );
+
+ //
+ // Set up the object attributes.
+ //
+
+ RtlInitUnicodeString( &uRdrName, RdrPrefix );
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &uRdrName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ ntstatus = NtOpenFile( &handleRdr,
+ SYNCHRONIZE | FILE_LIST_DIRECTORY,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT );
+
+ if ( !NT_SUCCESS(ntstatus) )
+ goto CleanExit;
+
+ //
+ // Fill out the request packet for FSCTL_NWR_NDS_LIST_TREES;
+ //
+
+ Request = ( PNWR_NDS_REQUEST_PACKET ) RequestBuffer;
+
+ Request->Parameters.ListTrees.NtUserNameLength = uNtUserName.Length;
+
+ RtlCopyMemory( &(Request->Parameters.ListTrees.NtUserName[0]),
+ uNtUserName.Buffer,
+ uNtUserName.Length );
+
+ RequestSize = sizeof( Request->Parameters.ListTrees ) +
+ uNtUserName.Length +
+ sizeof( DWORD );
+
+ ntstatus = NtFsControlFile( handleRdr,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_LIST_TREES,
+ (PVOID) Request,
+ RequestSize,
+ (PVOID) Buffer,
+ BufferSize );
+
+ if ( NT_SUCCESS( ntstatus ))
+ {
+ ntstatus = IoStatusBlock.Status;
+ *lpEntriesRead = Request->Parameters.ListTrees.TreesReturned;
+ *lpUserLUID = Request->Parameters.ListTrees.UserLuid.LowPart;
+ }
+
+CleanExit:
+
+ if ( handleRdr != NULL )
+ NtClose( handleRdr );
+
+ return RtlNtStatusToDosError( ntstatus );
+}
+
+