1465 lines
36 KiB
C
1465 lines
36 KiB
C
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
gateway.c
|
|
|
|
Abstract:
|
|
|
|
This module contains gateway devices routines supported by
|
|
NetWare Workstation service.
|
|
|
|
Author:
|
|
|
|
Chuck Y Chan (ChuckC) 31-Oct-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <nw.h>
|
|
#include <handle.h>
|
|
#include <nwreg.h>
|
|
#include <nwlsa.h>
|
|
#include <nwapi.h>
|
|
|
|
#include <lmcons.h>
|
|
#include <lmshare.h>
|
|
|
|
#include <winsta.h>
|
|
#include <winbasep.h> //DosPathToSessionPath
|
|
|
|
|
|
extern BOOL NwLUIDDeviceMapsEnabled;
|
|
|
|
//
|
|
//-------------------------------------------------------------------//
|
|
// //
|
|
// External Function Prototypes //
|
|
// //
|
|
//-------------------------------------------------------------------//
|
|
//
|
|
// GetProcAddress typedef for winsta.dll function WinStationEnumerateW
|
|
//
|
|
typedef BOOLEAN (*PWINSTATION_ENUMERATE) (
|
|
HANDLE hServer,
|
|
PSESSIONIDW *ppLogonId,
|
|
PULONG pEntries
|
|
);
|
|
//
|
|
// GetProcAddress typedef for winsta.dll function WinStationFreeMemory
|
|
//
|
|
typedef BOOLEAN (*PWINSTATION_FREE_MEMORY) ( PVOID);
|
|
|
|
LPTSTR
|
|
NwReturnSessionPath(
|
|
IN LPTSTR LocalDeviceName
|
|
);
|
|
|
|
//-------------------------------------------------------------------//
|
|
// //
|
|
// Local Function Prototypes //
|
|
// //
|
|
//-------------------------------------------------------------------//
|
|
|
|
DWORD
|
|
NwPopulateGWDosDevice(
|
|
LPWSTR DeviceName,
|
|
LPWSTR GetwayPath
|
|
);
|
|
//
|
|
// wrapper round the RPC routines.
|
|
//
|
|
|
|
DWORD
|
|
NwrEnumGWDevices(
|
|
LPWSTR Reserved,
|
|
PDWORD Index,
|
|
LPBYTE Buffer,
|
|
DWORD BufferSize,
|
|
LPDWORD BytesNeeded,
|
|
LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine enumerates the special gateway devices (redirections)
|
|
that are cureently in use.
|
|
|
|
Arguments:
|
|
|
|
Index - Point to start enumeration. Should be zero for first call.
|
|
This is set by the function and can be used to resume the
|
|
enumeration.
|
|
|
|
Buffer - buffer for return data
|
|
|
|
BufferSize - size of buffer in bytes
|
|
|
|
BytesNeeded - number of bytes needed to return all the data
|
|
|
|
EntriesRead - number of entries read
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error. If NO_ERROR or ERROR_MORE_DATA
|
|
then EntriesRead will indicated the number of valid entries in buffer.
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
return ( NwEnumerateGWDevices(
|
|
Index,
|
|
Buffer,
|
|
BufferSize,
|
|
BytesNeeded,
|
|
EntriesRead
|
|
) ) ;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrAddGWDevice(
|
|
LPWSTR Reserved,
|
|
LPWSTR DeviceName,
|
|
LPWSTR RemoteName,
|
|
LPWSTR AccountName,
|
|
LPWSTR Password,
|
|
DWORD Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds a gateway redirection.
|
|
|
|
Arguments:
|
|
|
|
DeviceName - the drive to redirect
|
|
|
|
RemoteName - the remote network resource to redirect to
|
|
|
|
Flags - supplies the options (eg. UpdateRegistry & make this sticky)
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD status ;
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
//
|
|
// make connection to the server to ensure we have a connection.
|
|
// if GatewayConnectionAlways is false, the function will immediately
|
|
// delete the connection, so this will just be an access check.
|
|
//
|
|
status = NwCreateGWConnection( RemoteName,
|
|
AccountName,
|
|
Password,
|
|
GatewayConnectionAlways) ;
|
|
|
|
if (status != NO_ERROR)
|
|
{
|
|
return status ;
|
|
}
|
|
|
|
//
|
|
// make the symbolic link
|
|
//
|
|
return ( NwCreateGWDevice(
|
|
DeviceName,
|
|
RemoteName,
|
|
Flags
|
|
) ) ;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrDeleteGWDevice(
|
|
LPWSTR Reserved,
|
|
LPWSTR DeviceName,
|
|
DWORD Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine enumerates the special gateway devices (redirections)
|
|
that are cureently in use.
|
|
|
|
Arguments:
|
|
|
|
Index - Point to start enumeration. Should be zero for first call.
|
|
This is set by the function and can be used to resume the
|
|
enumeration.
|
|
|
|
Buffer - buffer for return data
|
|
|
|
BufferSize - size of buffer in bytes
|
|
|
|
BytesNeeded - number of bytes needed to return all the data
|
|
|
|
EntriesRead - number of entries read
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
return ( NwRemoveGWDevice(
|
|
DeviceName,
|
|
Flags
|
|
) ) ;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrQueryGatewayAccount(
|
|
LPWSTR Reserved,
|
|
LPWSTR AccountName,
|
|
DWORD AccountNameLen,
|
|
LPDWORD AccountCharsNeeded,
|
|
LPWSTR Password,
|
|
DWORD PasswordLen,
|
|
LPDWORD PasswordCharsNeeded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Query the gateway account info. specifically, the Account name and
|
|
the passeord stored as an LSA secret.
|
|
|
|
Arguments:
|
|
|
|
AccountName - buffer used to return account name
|
|
|
|
AccountNameLen - length of buffer
|
|
|
|
AccountCharsNeeded - number of chars needed. only set properly if
|
|
AccountNameLen is too small.
|
|
|
|
Password - buffer used to return account name
|
|
|
|
PasswordLen - length of buffer
|
|
|
|
PasswordCharsNeeded - number of chars needed, only set properly if
|
|
PasswordLen is too small.
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
return ( NwQueryGWAccount(
|
|
AccountName,
|
|
AccountNameLen,
|
|
AccountCharsNeeded,
|
|
Password,
|
|
PasswordLen,
|
|
PasswordCharsNeeded
|
|
) ) ;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwrSetGatewayAccount(
|
|
LPWSTR Reserved,
|
|
LPWSTR AccountName,
|
|
LPWSTR Password
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the account and password to be used for gateway access.
|
|
|
|
Arguments:
|
|
|
|
AccountName - the account (NULL terminated)
|
|
|
|
Password - the password string (NULL terminated)
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
return ( NwSetGWAccount(
|
|
AccountName,
|
|
Password
|
|
) ) ;
|
|
}
|
|
|
|
|
|
//
|
|
// actual functions
|
|
//
|
|
|
|
|
|
|
|
DWORD
|
|
NwEnumerateGWDevices(
|
|
LPDWORD Index,
|
|
LPBYTE Buffer,
|
|
DWORD BufferSize,
|
|
LPDWORD BytesNeeded,
|
|
LPDWORD EntriesRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine enumerates the special gateway devices (redirections)
|
|
that are cureently in use.
|
|
|
|
Arguments:
|
|
|
|
Index - Point to start enumeration. Should be zero for first call.
|
|
This is set by the function and can be used to resume the
|
|
enumeration.
|
|
|
|
Buffer - buffer for return data
|
|
|
|
BufferSize - size of buffer in bytes
|
|
|
|
BytesNeeded - number of bytes needed to return all the data
|
|
|
|
EntriesRead - number of entries read
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD NwRdrNameLength, NwProviderNameSize ;
|
|
DWORD i, status ;
|
|
DWORD Length, Count, BytesRequired, SkipCount ;
|
|
WCHAR Drive[3] ;
|
|
WCHAR Path[MAX_PATH+1] ;
|
|
NETRESOURCEW *lpNetRes = NULL ;
|
|
LPBYTE BufferEnd = NULL ;
|
|
|
|
if (!Buffer)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
lpNetRes = (NETRESOURCEW *) Buffer;
|
|
BufferEnd = Buffer + ROUND_DOWN_COUNT(BufferSize,ALIGN_WCHAR);
|
|
|
|
//
|
|
// init the parts of the drives string we never change
|
|
//
|
|
Drive[1] = L':' ;
|
|
Drive[2] = 0 ;
|
|
|
|
Count = 0 ;
|
|
BytesRequired = 0 ;
|
|
SkipCount = *Index ;
|
|
NwProviderNameSize = wcslen(NwProviderName) + 1 ;
|
|
NwRdrNameLength = sizeof(DD_NWFS_DEVICE_NAME_U)/sizeof(WCHAR) - 1 ;
|
|
|
|
|
|
//
|
|
// for all logical drives
|
|
//
|
|
for (i = 0; i <26 ; i++)
|
|
{
|
|
BOOL GatewayDrive = FALSE ;
|
|
|
|
Drive[0] = L'A' + (USHORT)i ;
|
|
|
|
//
|
|
// get the symbolic link
|
|
//
|
|
Length = QueryDosDeviceW(Drive,
|
|
Path,
|
|
sizeof(Path)/sizeof(Path[0])) ;
|
|
|
|
//
|
|
// the value must be at least as long as our device name
|
|
//
|
|
if (Length >= NwRdrNameLength + 4)
|
|
{
|
|
//
|
|
// and it must match the following criteria:
|
|
// 1) start with \device\nwrdr
|
|
// 2) must have '\' after \device\nwrdr
|
|
// 3) must not have colon (ie. must be`
|
|
// \\device\nwrdr\server\share, and not
|
|
// \\device\nwrdr\x:\server\share
|
|
//
|
|
|
|
if ((_wcsnicmp(Path,DD_NWFS_DEVICE_NAME_U,NwRdrNameLength)
|
|
== 0)
|
|
&& (Path[NwRdrNameLength] == '\\')
|
|
&& (Path[NwRdrNameLength+2] != ':'))
|
|
{
|
|
//
|
|
// if this is an indexed read, skip the first N.
|
|
// this is inefficient, but we do not expect to
|
|
// have to go thru this very often. there are few
|
|
// such devices, and any reasonable buffer (even 1K)
|
|
// should get them all first time.
|
|
//
|
|
|
|
if (SkipCount)
|
|
SkipCount-- ;
|
|
else
|
|
GatewayDrive = TRUE ; // found a drive we want
|
|
}
|
|
}
|
|
|
|
if (GatewayDrive)
|
|
{
|
|
//
|
|
// we meet all criteria above
|
|
//
|
|
|
|
DWORD UncSize ;
|
|
|
|
UncSize = Length - NwRdrNameLength + 2 ;
|
|
BytesRequired += ( sizeof(NETRESOURCE) +
|
|
(UncSize * sizeof(WCHAR)) +
|
|
(NwProviderNameSize * sizeof(WCHAR)) +
|
|
(3 * sizeof(WCHAR))) ; // 3 for drive, X:\0
|
|
|
|
if (BytesRequired <= BufferSize)
|
|
{
|
|
LPWSTR lpStr = (LPWSTR) BufferEnd ;
|
|
|
|
Count++ ;
|
|
|
|
//
|
|
// copy the drive name
|
|
//
|
|
lpStr -= 3 ;
|
|
wcscpy(lpStr, Drive) ;
|
|
lpNetRes->lpLocalName = (LPWSTR) ((LPBYTE)lpStr - Buffer) ;
|
|
|
|
//
|
|
// copy the UNC name
|
|
//
|
|
lpStr -= UncSize ; // for the UNC name
|
|
lpStr[0] = L'\\' ;
|
|
wcscpy(lpStr+1, Path+NwRdrNameLength) ;
|
|
lpNetRes->lpRemoteName = (LPWSTR) ((LPBYTE)lpStr - Buffer) ;
|
|
|
|
//
|
|
// copy the provider name
|
|
//
|
|
lpStr -= NwProviderNameSize ; // for the provider name
|
|
wcscpy(lpStr, NwProviderName) ;
|
|
lpNetRes->lpProvider = (LPWSTR) ((LPBYTE)lpStr - Buffer) ;
|
|
|
|
//
|
|
// set up the rest of the structure
|
|
//
|
|
lpNetRes->dwScope = RESOURCE_CONNECTED ;
|
|
lpNetRes->dwType = RESOURCETYPE_DISK ;
|
|
lpNetRes->dwDisplayType = 0 ;
|
|
lpNetRes->dwUsage = 0 ;
|
|
lpNetRes->lpComment = 0 ;
|
|
|
|
lpNetRes++ ;
|
|
BufferEnd = (LPBYTE) lpStr ;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
*EntriesRead = Count ; // set number of entries
|
|
*Index += Count ; // move index
|
|
*BytesNeeded = BytesRequired ; // set bytes needed
|
|
|
|
if (BytesRequired == 0) // no info left
|
|
return (ERROR_NO_MORE_ITEMS) ;
|
|
|
|
if (BytesRequired > BufferSize)
|
|
{
|
|
return (ERROR_MORE_DATA) ;
|
|
}
|
|
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwCreateGWDevice(
|
|
LPWSTR DeviceName,
|
|
LPWSTR RemoteName,
|
|
DWORD Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds a gateway redirection.
|
|
|
|
Arguments:
|
|
|
|
DeviceName - the drive to redirect
|
|
|
|
RemoteName - the remote network resource to redirect to
|
|
|
|
Flags - supplies the options (eg. UpdateRegistry & make this sticky)
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
LPWSTR ConnectName = NULL;
|
|
DWORD status ;
|
|
WCHAR Path [MAX_PATH + 1] ;
|
|
|
|
//
|
|
// validate/canon the name. Use a drive to specific we allow UNC only.
|
|
//
|
|
if ((status = NwLibCanonRemoteName( L"A:",
|
|
RemoteName,
|
|
&ConnectName,
|
|
NULL
|
|
)) != NO_ERROR)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// build up the full name of \device\nwrdr\server\volume
|
|
//
|
|
wcscpy(Path, DD_NWFS_DEVICE_NAME_U) ;
|
|
wcscat(Path, ConnectName+1 ) ;
|
|
|
|
//
|
|
// create the symbolic link, Gateway specific, since there is no true user contacts
|
|
//
|
|
status = NwCreateSymbolicLink(DeviceName, Path, TRUE, FALSE) ;
|
|
|
|
(void) LocalFree((HLOCAL) ConnectName);
|
|
|
|
//
|
|
// if update registry is set, write it out
|
|
//
|
|
if ((status == NO_ERROR) && (Flags & NW_GW_UPDATE_REGISTRY))
|
|
{
|
|
HKEY hKey ;
|
|
DWORD dwDisposition ;
|
|
|
|
//
|
|
//
|
|
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
|
// \NWCWorkstation\Drives (create it if not there)
|
|
//
|
|
status = RegCreateKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
NW_WORKSTATION_GATEWAY_DRIVES,
|
|
0,
|
|
L"",
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE, // desired access
|
|
NULL, // default security
|
|
&hKey,
|
|
&dwDisposition // ignored
|
|
);
|
|
|
|
if ( status )
|
|
return status ;
|
|
|
|
status = RegSetValueExW(
|
|
hKey,
|
|
DeviceName,
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE) RemoteName,
|
|
(wcslen(RemoteName)+1) * sizeof(WCHAR)) ;
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
|
|
if (status == ERROR_SUCCESS && IsTerminalServer() &&
|
|
(NwLUIDDeviceMapsEnabled == FALSE)) {
|
|
status = NwPopulateGWDosDevice(DeviceName, Path) ;
|
|
}
|
|
}
|
|
|
|
return status ;
|
|
|
|
}
|
|
|
|
DWORD
|
|
NwRemoveGWDevice(
|
|
LPWSTR DeviceName,
|
|
DWORD Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes a gateway redirection.
|
|
|
|
Arguments:
|
|
|
|
DeviceName - the drive to delete
|
|
|
|
Flags - supplies the options (eg. UpdateRegistry & make this sticky)
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD status ;
|
|
LPWSTR Local = NULL ;
|
|
//LPWSTR SessionDeviceName;
|
|
|
|
if (status = NwLibCanonLocalName(DeviceName,
|
|
&Local,
|
|
NULL))
|
|
return status ;
|
|
|
|
//SessionDeviceName = NwReturnSessionPath(Local);
|
|
//if ( SessionDeviceName == NULL ) {
|
|
// return ERROR_NOT_ENOUGH_MEMORY;
|
|
//}
|
|
|
|
//
|
|
// delete the symbolic link
|
|
//
|
|
if (! DefineDosDeviceW(DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH,
|
|
Local,
|
|
//SessionDeviceName,
|
|
DD_NWFS_DEVICE_NAME_U))
|
|
{
|
|
status = ERROR_INVALID_DRIVE ;
|
|
}
|
|
|
|
//if ( SessionDeviceName ) {
|
|
// LocalFree( SessionDeviceName );
|
|
//}
|
|
|
|
//
|
|
// If cleanup deleted (dangling) share is set go do it now.
|
|
// We loop thru all the shares looking for one that matches that drive.
|
|
// Then we ask the server to nuke that dangling share.
|
|
//
|
|
if ((status == NO_ERROR) && (Flags & NW_GW_CLEANUP_DELETED))
|
|
{
|
|
HKEY hKey ;
|
|
DWORD err ;
|
|
|
|
//
|
|
//
|
|
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
|
// \NWCWorkstation\Shares
|
|
//
|
|
err = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
NW_WORKSTATION_GATEWAY_SHARES,
|
|
REG_OPTION_NON_VOLATILE, // options
|
|
KEY_READ | KEY_WRITE, // desired access
|
|
&hKey
|
|
);
|
|
|
|
if (err == NO_ERROR)
|
|
{
|
|
WCHAR Path[MAX_PATH + 1], ShareName[MAX_PATH+1] ;
|
|
DWORD dwType, i = 0, dwPathSize, dwShareNameSize ;
|
|
|
|
do {
|
|
|
|
dwPathSize = sizeof(Path),
|
|
dwShareNameSize = sizeof(ShareName)/sizeof(ShareName[0]) ;
|
|
dwType = REG_SZ ;
|
|
|
|
err = RegEnumValueW(hKey,
|
|
i,
|
|
ShareName,
|
|
&dwShareNameSize,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)Path,
|
|
&dwPathSize) ;
|
|
|
|
//
|
|
// Look for matching drive, eg. "X:"
|
|
// If have match, cleanup as best we can and break out now.
|
|
//
|
|
if ((err == NO_ERROR) &&
|
|
(_wcsnicmp(Path,DeviceName,2) == 0))
|
|
{
|
|
(void) NetShareDelSticky( NULL,
|
|
ShareName,
|
|
0 ) ;
|
|
(void) RegDeleteValueW(hKey,
|
|
ShareName) ;
|
|
break ;
|
|
}
|
|
|
|
i++ ;
|
|
|
|
} while (err == NO_ERROR) ;
|
|
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// if update registry is set, write it out
|
|
//
|
|
if ((status == NO_ERROR) && (Flags & NW_GW_UPDATE_REGISTRY))
|
|
{
|
|
HKEY hKey ;
|
|
WCHAR Path[MAX_PATH + 1] ;
|
|
DWORD dwType, dwSize = sizeof(Path) ;
|
|
|
|
//
|
|
//
|
|
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
|
// \NWCWorkstation\Drives
|
|
//
|
|
status = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
NW_WORKSTATION_GATEWAY_DRIVES,
|
|
REG_OPTION_NON_VOLATILE, // options
|
|
KEY_READ | KEY_WRITE, // desired access
|
|
&hKey
|
|
);
|
|
|
|
if ( status )
|
|
goto ExitPoint ;
|
|
|
|
if (GatewayConnectionAlways)
|
|
{
|
|
//
|
|
// Read the remote path and delete the connection
|
|
// if we made one in the first place.
|
|
//
|
|
status = RegQueryValueExW(
|
|
hKey,
|
|
Local,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) Path,
|
|
&dwSize
|
|
);
|
|
|
|
if (status == NO_ERROR)
|
|
{
|
|
(void) NwDeleteGWConnection(Path) ;
|
|
}
|
|
}
|
|
|
|
status = RegDeleteValueW(
|
|
hKey,
|
|
DeviceName
|
|
) ;
|
|
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
ExitPoint:
|
|
|
|
if (Local)
|
|
(void) LocalFree((HLOCAL)Local) ;
|
|
|
|
return status ;
|
|
}
|
|
|
|
DWORD
|
|
NwGetGatewayResource(
|
|
IN LPWSTR LocalName,
|
|
OUT LPWSTR RemoteName,
|
|
IN DWORD RemoteNameLen,
|
|
OUT LPDWORD CharsRequired
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
For a gateway devicename, get the network resource associated with it.
|
|
|
|
Arguments:
|
|
|
|
LocalName - name of devive to query
|
|
|
|
RemoteName - buffer to return the network resource
|
|
|
|
RemoteNameLen - size of buffer (chars)
|
|
|
|
CharsRequired - the number of chars needed
|
|
|
|
Return Value:
|
|
|
|
WN_SUCCESS - success (the device is a gateway redirection)
|
|
|
|
WN_MORE_DATA - buffer too small, but device is a gateway redirection
|
|
|
|
WN_NOT_CONNECTED - not a gateway redirection
|
|
|
|
--*/
|
|
{
|
|
WCHAR Path[MAX_PATH+1] ;
|
|
DWORD Length ;
|
|
DWORD NwRdrNameLength ;
|
|
|
|
NwRdrNameLength = sizeof(DD_NWFS_DEVICE_NAME_U)/sizeof(WCHAR) - 1 ;
|
|
|
|
//
|
|
// retrieve symbolic link for the device
|
|
//
|
|
Length = QueryDosDeviceW(LocalName,
|
|
Path,
|
|
sizeof(Path)/sizeof(Path[0])) ;
|
|
|
|
//
|
|
// the result is only interesting if it can at least fit:
|
|
// \device\nwrdr\x\y
|
|
//
|
|
if (Length >= NwRdrNameLength + 4)
|
|
{
|
|
//
|
|
// check to make sure that the prefix is coreect, and that
|
|
// it is not of form: \device\nwrdr\x:\...
|
|
//
|
|
if ((_wcsnicmp(Path,DD_NWFS_DEVICE_NAME_U,NwRdrNameLength) == 0)
|
|
&& (Path[NwRdrNameLength] == '\\')
|
|
&& (Path[NwRdrNameLength+2] != ':'))
|
|
{
|
|
//
|
|
// check buffer size
|
|
//
|
|
if (RemoteNameLen < ((Length - NwRdrNameLength) + 1))
|
|
{
|
|
if (CharsRequired)
|
|
*CharsRequired = ((Length - NwRdrNameLength) + 1) ;
|
|
return WN_MORE_DATA ;
|
|
}
|
|
|
|
*RemoteName = L'\\' ;
|
|
wcscpy(RemoteName+1,Path+NwRdrNameLength) ;
|
|
return WN_SUCCESS ;
|
|
}
|
|
}
|
|
|
|
return WN_NOT_CONNECTED ;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwQueryGWAccount(
|
|
LPWSTR AccountName,
|
|
DWORD AccountNameLen,
|
|
LPDWORD AccountCharsNeeded,
|
|
LPWSTR Password,
|
|
DWORD PasswordLen,
|
|
LPDWORD PasswordCharsNeeded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Query the gateway account info. specifically, the Account name and
|
|
the passeord stored as an LSA secret.
|
|
|
|
Arguments:
|
|
|
|
AccountName - buffer used to return account name
|
|
|
|
AccountNameLen - length of buffer
|
|
|
|
AccountCharsNeeded - number of chars needed. only set properly if
|
|
AccountNameLen is too small.
|
|
|
|
Password - buffer used to return account name
|
|
|
|
PasswordLen - length of buffer
|
|
|
|
PasswordCharsNeeded - number of chars needed, only set properly if
|
|
PasswordLen is too small.
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD status = NO_ERROR ;
|
|
LONG RegError;
|
|
|
|
HKEY WkstaKey = NULL;
|
|
LPWSTR GatewayAccount = NULL;
|
|
|
|
PUNICODE_STRING StoredPassword = NULL;
|
|
PUNICODE_STRING StoredOldPassword = NULL;
|
|
|
|
if ( !AccountName || !Password )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*AccountCharsNeeded = 0 ;
|
|
*PasswordCharsNeeded = 0 ;
|
|
|
|
//
|
|
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
|
// \NWCWorkstation\Parameters
|
|
//
|
|
RegError = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
NW_WORKSTATION_REGKEY,
|
|
REG_OPTION_NON_VOLATILE, // options
|
|
KEY_READ, // desired access
|
|
&WkstaKey
|
|
);
|
|
|
|
if (RegError != ERROR_SUCCESS)
|
|
{
|
|
return (RegError);
|
|
}
|
|
|
|
//
|
|
// Read the gateway account from the registry.
|
|
//
|
|
status = NwReadRegValue(
|
|
WkstaKey,
|
|
NW_GATEWAYACCOUNT_VALUENAME,
|
|
&GatewayAccount
|
|
);
|
|
|
|
if (status != NO_ERROR)
|
|
{
|
|
if (status != ERROR_FILE_NOT_FOUND)
|
|
goto CleanExit;
|
|
|
|
if (AccountNameLen > 0)
|
|
*AccountName = 0 ;
|
|
status = NO_ERROR ;
|
|
}
|
|
else
|
|
{
|
|
*AccountCharsNeeded = wcslen(GatewayAccount) + 1 ;
|
|
if (*AccountCharsNeeded > AccountNameLen)
|
|
{
|
|
status = ERROR_INSUFFICIENT_BUFFER ;
|
|
goto CleanExit;
|
|
}
|
|
wcscpy(AccountName,GatewayAccount);
|
|
}
|
|
|
|
//
|
|
// Read the password from its secret object in LSA.
|
|
//
|
|
status = NwGetPassword(
|
|
GATEWAY_USER,
|
|
&StoredPassword, // Must be freed with LsaFreeMemory
|
|
&StoredOldPassword // Must be freed with LsaFreeMemory
|
|
);
|
|
|
|
if (status != NO_ERROR)
|
|
{
|
|
if (status != ERROR_FILE_NOT_FOUND)
|
|
goto CleanExit;
|
|
|
|
if (PasswordLen > 0)
|
|
*Password = 0 ;
|
|
|
|
status = NO_ERROR ;
|
|
}
|
|
else
|
|
{
|
|
*PasswordCharsNeeded = StoredPassword->Length/sizeof(WCHAR) + 1 ;
|
|
if ((StoredPassword->Length/sizeof(WCHAR)) >= PasswordLen)
|
|
{
|
|
status = ERROR_INSUFFICIENT_BUFFER ;
|
|
goto CleanExit;
|
|
}
|
|
wcsncpy(Password,
|
|
StoredPassword->Buffer,
|
|
StoredPassword->Length/sizeof(WCHAR));
|
|
Password[StoredPassword->Length/sizeof(WCHAR)] = 0 ;
|
|
}
|
|
|
|
|
|
CleanExit:
|
|
|
|
if (StoredPassword != NULL) {
|
|
(void) LsaFreeMemory((PVOID) StoredPassword);
|
|
}
|
|
|
|
if (StoredOldPassword != NULL) {
|
|
(void) LsaFreeMemory((PVOID) StoredOldPassword);
|
|
}
|
|
|
|
if (GatewayAccount != NULL) {
|
|
(void) LocalFree((HLOCAL) GatewayAccount);
|
|
}
|
|
|
|
(void) RegCloseKey(WkstaKey);
|
|
|
|
return status ;
|
|
}
|
|
|
|
DWORD
|
|
NwSetGWAccount(
|
|
LPWSTR AccountName,
|
|
LPWSTR Password
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the account and password to be used for gateway access.
|
|
|
|
Arguments:
|
|
|
|
AccountName - the account (NULL terminated)
|
|
|
|
Password - the password string (NULL terminated)
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD status ;
|
|
HKEY WkstaKey = NULL;
|
|
|
|
//
|
|
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
|
// \NWCWorkstation\Parameters
|
|
//
|
|
status = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
NW_WORKSTATION_REGKEY,
|
|
REG_OPTION_NON_VOLATILE, // options
|
|
KEY_WRITE, // desired access
|
|
&WkstaKey
|
|
);
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
return (status);
|
|
}
|
|
|
|
//
|
|
// Write the account name out
|
|
//
|
|
status = RegSetValueExW(
|
|
WkstaKey,
|
|
NW_GATEWAYACCOUNT_VALUENAME,
|
|
0,
|
|
REG_SZ,
|
|
(LPVOID) AccountName,
|
|
(wcslen(AccountName) + 1) * sizeof(WCHAR)
|
|
);
|
|
|
|
if (status == NO_ERROR)
|
|
{
|
|
status = NwSetPassword(
|
|
GATEWAY_USER,
|
|
Password) ;
|
|
}
|
|
|
|
return status ;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwCreateRedirections(
|
|
LPWSTR Account,
|
|
LPWSTR Password
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create the gateway redirections from what is stored in registry.
|
|
As we go along, we validate that we have access to it using the
|
|
gateway account.
|
|
|
|
Arguments:
|
|
|
|
AccountName - the account (NULL terminated)
|
|
|
|
Password - the password string (NULL terminated)
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD err, i, type ;
|
|
HKEY hKey ;
|
|
FILETIME FileTime ;
|
|
WCHAR Class[256], Device[64], Path[MAX_PATH+1] ;
|
|
DWORD dwClass, dwSubKeys, dwMaxSubKey, dwMaxClass,
|
|
dwValues, dwMaxValueName, dwMaxValueData, dwSDLength,
|
|
dwDeviceLength, dwPathLength ;
|
|
|
|
//
|
|
//
|
|
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
|
// \NWCGateway\Parameters
|
|
//
|
|
err = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
NW_WORKSTATION_GATEWAY_DRIVES,
|
|
REG_OPTION_NON_VOLATILE, // options
|
|
KEY_READ, // desired access
|
|
&hKey
|
|
);
|
|
|
|
if ( err )
|
|
return err ;
|
|
|
|
dwClass = sizeof(Class)/sizeof(Class[0]) ;
|
|
err = RegQueryInfoKeyW(hKey,
|
|
Class,
|
|
&dwClass,
|
|
NULL,
|
|
&dwSubKeys,
|
|
&dwMaxSubKey,
|
|
&dwMaxClass,
|
|
&dwValues,
|
|
&dwMaxValueName,
|
|
&dwMaxValueData,
|
|
&dwSDLength,
|
|
&FileTime) ;
|
|
if ( err )
|
|
{
|
|
RegCloseKey( hKey );
|
|
return err ;
|
|
}
|
|
|
|
//
|
|
// for each value we have a redirection to recreate
|
|
//
|
|
for (i = 0; i < dwValues; i++)
|
|
{
|
|
dwDeviceLength = sizeof(Device)/sizeof(Device[0]) ;
|
|
dwPathLength = sizeof(Path) ;
|
|
type = REG_SZ ;
|
|
err = RegEnumValueW(hKey,
|
|
i,
|
|
Device,
|
|
&dwDeviceLength,
|
|
NULL,
|
|
&type,
|
|
(LPBYTE)Path,
|
|
&dwPathLength) ;
|
|
|
|
//
|
|
// connect to the server. this will take up a connection but
|
|
// it will also make sure we have one. on a low limit server, if
|
|
// we rely on UNC then it is quite likely that other people will
|
|
// come along & use up all the connections, preventing the Gateway
|
|
// from getting to it.
|
|
//
|
|
// user may turn this off by setting Registry value that results
|
|
// GatewayConnectionAlways being false.
|
|
//
|
|
// regardless of result, we carry on. so if server is down & comes
|
|
// up later, the symbolic link to UNC will still work.
|
|
//
|
|
if (!err)
|
|
{
|
|
(void) NwCreateGWConnection( Path,
|
|
Account,
|
|
Password,
|
|
GatewayConnectionAlways) ;
|
|
}
|
|
|
|
//
|
|
// create the symbolic link
|
|
//
|
|
if (!err)
|
|
{
|
|
err = NwCreateGWDevice(Device, Path, 0L) ;
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
//
|
|
// log the error in the event log
|
|
//
|
|
|
|
WCHAR Number[16] ;
|
|
LPWSTR InsertStrings[3] ;
|
|
|
|
wsprintfW(Number, L"%d", err) ;
|
|
InsertStrings[0] = Device ;
|
|
InsertStrings[1] = Path ;
|
|
InsertStrings[2] = Number ;
|
|
|
|
NwLogEvent(EVENT_NWWKSTA_CANNOT_REDIRECT_DEVICES,
|
|
3,
|
|
InsertStrings,
|
|
0) ;
|
|
}
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
DWORD
|
|
NwDeleteRedirections(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete all gateway devices
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
LPBYTE Buffer ;
|
|
DWORD i, status, Index, BufferSize, EntriesRead, BytesNeeded ;
|
|
LPNETRESOURCE lpNetRes ;
|
|
|
|
Index = 0 ;
|
|
|
|
//
|
|
// below is good initial guess
|
|
//
|
|
BufferSize = 26 * (sizeof(NETRESOURCE) +
|
|
(3 + MAX_PATH + 1 + MAX_PATH + 1) * sizeof(WCHAR)) ;
|
|
Buffer = (LPBYTE) LocalAlloc(LPTR, BufferSize) ;
|
|
|
|
if (!Buffer)
|
|
return (GetLastError()) ;
|
|
|
|
lpNetRes = (LPNETRESOURCE) Buffer ;
|
|
|
|
status = NwrEnumGWDevices(NULL,
|
|
&Index,
|
|
Buffer,
|
|
BufferSize,
|
|
&BytesNeeded,
|
|
&EntriesRead) ;
|
|
|
|
//
|
|
// reallocate as need
|
|
//
|
|
if (status == ERROR_MORE_DATA || status == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
Buffer = (LPBYTE) LocalReAlloc((HLOCAL)Buffer,
|
|
BytesNeeded,
|
|
LMEM_ZEROINIT) ;
|
|
if (!Buffer)
|
|
return (GetLastError()) ;
|
|
Index = 0 ;
|
|
BufferSize = BytesNeeded ;
|
|
status = NwrEnumGWDevices(NULL,
|
|
&Index,
|
|
Buffer,
|
|
BufferSize,
|
|
&BytesNeeded,
|
|
&EntriesRead) ;
|
|
|
|
}
|
|
|
|
if (status != NO_ERROR)
|
|
return status ;
|
|
|
|
//
|
|
// loop thru and delete all the devices
|
|
//
|
|
for (i = 0; i < EntriesRead; i++)
|
|
{
|
|
status = NwrDeleteGWDevice(NULL,
|
|
(LPWSTR)((LPBYTE)Buffer +
|
|
(DWORD_PTR)lpNetRes->lpLocalName),
|
|
0L) ;
|
|
|
|
//
|
|
// no need report the error, since we are shutting down.
|
|
// there is no real deletion here - just removing the symbolic link.
|
|
//
|
|
|
|
lpNetRes++ ;
|
|
}
|
|
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwPopulateGWDosDevice(
|
|
IN LPWSTR DeviceName,
|
|
IN LPWSTR GatewayPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine poplaute the gateway dos device to all the active terminal sessions
|
|
|
|
Arguments:
|
|
|
|
DeviceName - the drive to redirect
|
|
|
|
GatewayPath - the remote network resource of the gateway drive
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD status = ERROR_SUCCESS;
|
|
HMODULE hwinsta = NULL;
|
|
PWINSTATION_ENUMERATE pfnWinStationEnumerate;
|
|
PWINSTATION_FREE_MEMORY pfnWinStationFreeMemory;
|
|
PSESSIONIDW pSessionIds = NULL;
|
|
ULONG SessionCount;
|
|
ULONG SessionId;
|
|
LPWSTR pSessionPath = NULL;
|
|
|
|
/*
|
|
* Dynmaically load the winsta.dll
|
|
*/
|
|
|
|
if ( (hwinsta = LoadLibraryW( L"WINSTA" )) == NULL ) {
|
|
status = ERROR_DLL_NOT_FOUND;
|
|
goto Exit;
|
|
}
|
|
pfnWinStationEnumerate = (PWINSTATION_ENUMERATE)
|
|
GetProcAddress( hwinsta, "WinStationEnumerateW" );
|
|
|
|
pfnWinStationFreeMemory = (PWINSTATION_FREE_MEMORY)
|
|
GetProcAddress( hwinsta, "WinStationFreeMemory" );
|
|
|
|
if (!pfnWinStationEnumerate || !pfnWinStationFreeMemory) {
|
|
status = ERROR_INVALID_DLL;
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* Enumerate Sessions
|
|
*/
|
|
|
|
if ( !pfnWinStationEnumerate( NULL, //Enumerate self
|
|
&pSessionIds,
|
|
&SessionCount ) ) {
|
|
status = GetLastError();
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* Loop through the session, skip the console, ie SessionId = 0
|
|
* Since the gateway device is always created for the console
|
|
*/
|
|
for ( SessionId = 1; SessionId < SessionCount; SessionId++ ) {
|
|
if (
|
|
(pSessionIds[SessionId].State != State_Idle) &&
|
|
(pSessionIds[SessionId].State != State_Down) &&
|
|
(pSessionIds[SessionId].State != State_Disconnected)
|
|
) {
|
|
|
|
WCHAR TempBuf[64];
|
|
//
|
|
// Create a Gateway Dos Device for those terminal sessions
|
|
//
|
|
if (!DosPathToSessionPath(
|
|
SessionId,
|
|
DeviceName,
|
|
&pSessionPath
|
|
)) {
|
|
status = GetLastError();
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
if (!QueryDosDeviceW(
|
|
pSessionPath,
|
|
TempBuf,
|
|
sizeof(TempBuf)
|
|
)) {
|
|
|
|
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
|
|
|
|
//
|
|
// Most likely failure occurred because our output
|
|
// buffer is too small. It still means someone already
|
|
// has an existing symbolic link for this device for this session.
|
|
// It is ok, just skip this session
|
|
//
|
|
continue;
|
|
}
|
|
// This path is OK
|
|
}
|
|
else {
|
|
//
|
|
// QueryDosDevice successfully an existing symbolic link--
|
|
// somebody is already using this device for this session.
|
|
// Skip this session and continue...
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create a symbolic link object to the device we are redirecting
|
|
//
|
|
if (! DefineDosDeviceW(
|
|
DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM,
|
|
pSessionPath,
|
|
GatewayPath
|
|
)) {
|
|
//Cannot create device for this session.
|
|
status = GetLastError();
|
|
goto Exit;
|
|
}
|
|
} //if (pSessionID...
|
|
} //for (SessionID
|
|
|
|
Exit:
|
|
if (pSessionIds) {
|
|
pfnWinStationFreeMemory( pSessionIds );
|
|
}
|
|
|
|
if (pSessionPath) {
|
|
LocalFree(pSessionPath);
|
|
}
|
|
|
|
if (hwinsta) {
|
|
FreeLibrary(hwinsta);
|
|
}
|
|
return status;
|
|
}
|