|
|
/*++
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 ); }
|