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

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;
}