windows-nt/Source/XPSP1/NT/ds/nw/svcdlls/nwwks/client/nwutil.c
2020-09-26 16:20:57 +08:00

921 lines
23 KiB
C

/*++
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 ))
{
//
// TRACKING - 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 ) {
return;
}
if ( pszUNCPath[0] == L' ') {
pszUNCPath++;
}
if ( ( pszUNCPath[0] != L'\\') || ( pszUNCPath[1] != L'\\') ) {
return;
}
//
// tommye - fix for bug 5005 - if there is a NW server having
// the same name as a NDS Tree, then NwIsNdsSyntax will return
// TRUE even though the path points to the server (not the tree).
// This was blowing up becuase the wschr was returning NULL, and
// wasn't being checked. If this returns NULL, then we'll make
// the assumption that we've got a server name after all.
//
if ( NwIsNdsSyntax( pszUNCPath ))
{
pszTemp = wcschr( pszUNCPath + 2, L'\\' ); // get past "\\"
if (pszTemp) {
wcscpy( pszServerName, pszTemp + 1 ); // get past "\"
if ( pszTemp = wcschr( pszServerName, L'.' )) {
*pszTemp = 0;
}
return;
}
}
//
// tommye
// Fall through - this must be a server name only
//
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;
}
//
// tommye - fix for bug 5005 - if there is a NW server having
// the same name as a NDS Tree, then NwIsNdsSyntax will return
// TRUE even though the path points to the server (not the tree).
// This was blowing up becuase the wschr was returning NULL, and
// wasn't being checked. If this returns NULL, then we'll make
// the assumption that we've got a server name after all.
//
if ( NwIsNdsSyntax( pszUNCPath ))
{
pszTemp = wcschr( pszUNCPath + 2, L'\\' ); // get past "\\"
if (pszTemp) {
wcscpy( pszShareName, pszTemp + 1 ); // get past "\"
if ( pszTemp = wcschr( pszShareName, L'.' )) {
*pszTemp = 0;
}
return;
}
}
//
// tommye
// Fall through - this must be a server name only
//
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_PTR 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_PTR 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_PTR 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:
//
// Note: This change added to fix NT bug 338991 on Win2000
//
if ( ntstatus == STATUS_BAD_NETWORK_PATH )
{
ntstatus = STATUS_ACCESS_DENIED;
}
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 );
}