You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3129 lines
80 KiB
3129 lines
80 KiB
/*++
|
|
|
|
Copyright (c) 1998, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sharing.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code for routines which support connection sharing
|
|
configuration.
|
|
|
|
Connection sharing involves a public (internet) interface, ordinarily
|
|
a dialup interface identified by phonebook/entry-name, as well as
|
|
a private (home) interface, required to be a lan interface.
|
|
|
|
On setting up connection sharing, the service is enabled if necessary,
|
|
and the private lan interface is configured with static address 169.254.0.1
|
|
via the TCP/IP 'SetAdapterIpAddress' API routine.
|
|
|
|
The name of the shared connection is stored in the registry along with
|
|
the GUID of the shared private LAN connection, under the registry key
|
|
HKLM\Software\Microsoft\SharedAccess\Parameters.
|
|
|
|
N.B. NT registry routines are used, to avoid the hit incurred by
|
|
going through the Win32 server.
|
|
|
|
Author:
|
|
|
|
Abolade Gbadegesin (aboladeg) 22-Apr-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#define _PNP_POWER_
|
|
#include <ndispnp.h>
|
|
#include <ntddip.h>
|
|
#include <winsock2.h>
|
|
#include <dhcpcapi.h>
|
|
#include <netconp.h>
|
|
|
|
#if 0
|
|
|
|
//
|
|
// Structure: CS_ADDRESS_INFORMATION
|
|
//
|
|
|
|
typedef struct _CS_ADDRESS_INFORMATION {
|
|
PKEY_VALUE_PARTIAL_INFORMATION IPAddress;
|
|
PKEY_VALUE_PARTIAL_INFORMATION SubnetMask;
|
|
PKEY_VALUE_PARTIAL_INFORMATION DefaultGateway;
|
|
PKEY_VALUE_PARTIAL_INFORMATION EnableDHCP;
|
|
} CS_ADDRESS_INFORMATION, *PCS_ADDRESS_INFORMATION;
|
|
|
|
//
|
|
// DHCPCSVC.DLL import prototype
|
|
//
|
|
|
|
typedef DWORD
|
|
(APIENTRY* PDHCPNOTIFYCONFIGCHANGE)(
|
|
LPWSTR,
|
|
LPWSTR,
|
|
BOOL,
|
|
DWORD,
|
|
DWORD,
|
|
DWORD,
|
|
SERVICE_ENABLE
|
|
);
|
|
|
|
#endif
|
|
|
|
//
|
|
// OLE entrypoints loaded dynamically
|
|
//
|
|
|
|
PCOINITIALIZEEX g_pCoInitializeEx;
|
|
PCOUNINITIALIZE g_pCoUninitialize;
|
|
PCOCREATEINSTANCE g_pCoCreateInstance;
|
|
PCOSETPROXYBLANKET g_pCoSetProxyBlanket;
|
|
PCOTASKMEMFREE g_pCoTaskMemFree;
|
|
|
|
//
|
|
// CONSTANT DEFINITIONS
|
|
//
|
|
|
|
#if 0
|
|
const CHAR c_szAllocateAndGetIpAddrTableFromStack[] =
|
|
"AllocateAndGetIpAddrTableFromStack";
|
|
#endif
|
|
const CHAR c_szCoInitializeEx[] = "CoInitializeEx";
|
|
const CHAR c_szCoUninitialize[] = "CoUninitialize";
|
|
const CHAR c_szCoCreateInstance[] = "CoCreateInstance";
|
|
const CHAR c_szCoSetProxyBlanket[] = "CoSetProxyBlanket";
|
|
const CHAR c_szCoTaskMemFree[] = "CoTaskMemFree";
|
|
#if 0
|
|
const CHAR c_szDhcpNotifyConfigChange[] = "DhcpNotifyConfigChange";
|
|
const CHAR c_szGetInterfaceInfo[] = "GetInterfaceInfo";
|
|
#endif
|
|
const CHAR c_szMprConfigBufferFree[] = "MprConfigBufferFree";
|
|
const CHAR c_szMprConfigServerConnect[] = "MprConfigServerConnect";
|
|
const CHAR c_szMprConfigServerDisconnect[] = "MprConfigServerDisconnect";
|
|
const CHAR c_szMprConfigTransportGetHandle[] = "MprConfigTransportGetHandle";
|
|
const CHAR c_szMprConfigTransportGetInfo[] = "MprConfigTransportGetInfo";
|
|
const CHAR c_szMprInfoBlockFind[] = "MprInfoBlockFind";
|
|
#if 0
|
|
const CHAR c_szSetAdapterIpAddress[] = "SetAdapterIpAddress";
|
|
#endif
|
|
const TCHAR c_szSharedAccess[] = TEXT("SharedAccess");
|
|
#if 0
|
|
const WCHAR c_szBackupDefaultGateway[] = L"BackupDefaultGateway";
|
|
const WCHAR c_szBackupEnableDHCP[] = L"BackupEnableDHCP";
|
|
const WCHAR c_szBackupIPAddress[] = L"BackupIPAddress";
|
|
const WCHAR c_szBackupSubnetMask[] = L"BackupSubnetMask";
|
|
const WCHAR c_szDefaultGateway[] = L"DefaultGateway";
|
|
const WCHAR c_szDevice[] = L"\\Device\\";
|
|
const WCHAR c_szDhcpcsvcDll[] = L"DHCPCSVC.DLL";
|
|
const WCHAR c_szEmpty[] = L"";
|
|
const WCHAR c_szEnableDHCP[] = L"EnableDHCP";
|
|
const WCHAR c_szInterfaces[] = L"Interfaces";
|
|
const WCHAR c_szIPAddress[] = L"IPAddress";
|
|
const WCHAR c_szIphlpapiDll[] = L"IPHLPAPI.DLL";
|
|
#endif
|
|
const WCHAR c_szMprapiDll[] = L"MPRAPI.DLL";
|
|
const WCHAR c_szMsTcpip[] = L"MS_TCPIP";
|
|
const WCHAR c_szOle32Dll[] = L"OLE32.DLL";
|
|
#if 0
|
|
const WCHAR c_szScopeAddress[] = L"ScopeAddress";
|
|
const WCHAR c_szScopeMask[] = L"ScopeMask";
|
|
#endif
|
|
const WCHAR c_szSharedAccessParametersKey[] =
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\SharedAccess"
|
|
L"\\Parameters";
|
|
#if 0
|
|
const WCHAR c_szSharedConnection[] = L"SharedConnection";
|
|
const WCHAR c_szSharedPrivateLan[] = L"SharedPrivateLan";
|
|
const WCHAR c_szSubnetMask[] = L"SubnetMask";
|
|
const WCHAR c_szTcpip[] = L"Tcpip";
|
|
const WCHAR c_szTcpipParametersKey[] =
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip"
|
|
L"\\Parameters";
|
|
const WCHAR c_szFirewallConnection[] = L"FirewallConnection";
|
|
const WCHAR c_szFirewallConnectionCount[] = L"FirewallConnectionCount";
|
|
#endif
|
|
|
|
//
|
|
// LOCAL VARIABLE DEFINITIONS
|
|
//
|
|
|
|
static BOOLEAN CsInitialized = FALSE;
|
|
static CRITICAL_SECTION CsCriticalSection;
|
|
static BOOLEAN CsDllMainCalled = FALSE;
|
|
static HINSTANCE CsOle32Dll = NULL;
|
|
|
|
//
|
|
// FUNCTION PROTOTYPES
|
|
//
|
|
|
|
#if 0
|
|
|
|
VOID
|
|
CspBackupAddressInformation(
|
|
HANDLE Key,
|
|
PCS_ADDRESS_INFORMATION AddressInformation
|
|
);
|
|
|
|
NTSTATUS
|
|
CspCaptureAddressInformation(
|
|
PWCHAR AdapterGuid,
|
|
PCS_ADDRESS_INFORMATION Information
|
|
);
|
|
|
|
VOID
|
|
CspCleanupAddressInformation(
|
|
PCS_ADDRESS_INFORMATION AddressInformation
|
|
);
|
|
|
|
NTSTATUS
|
|
CspRestoreAddressInformation(
|
|
HANDLE Key,
|
|
PWCHAR AdapterGuid
|
|
);
|
|
|
|
BOOLEAN
|
|
CspIsConnectionFwWorker(
|
|
LPRASSHARECONN ConnectionArray,
|
|
ULONG Count,
|
|
LPRASSHARECONN Connection,
|
|
ULONG *ConnNumber OUT OPTIONAL
|
|
);
|
|
|
|
ULONG
|
|
CspAddFirewallConnection(
|
|
LPRASSHARECONN Connection,
|
|
ULONG Number
|
|
);
|
|
|
|
ULONG
|
|
CspRemoveFirewallConnection(
|
|
LPRASSHARECONN Connection,
|
|
ULONG Position,
|
|
LPRASSHARECONN ConnectionArray,
|
|
ULONG Count
|
|
);
|
|
|
|
#endif
|
|
|
|
|
|
BOOL
|
|
CsDllMain(
|
|
ULONG Reason
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This pseudo-entrypoint is invoked by RASAPI32.DLL's DllMain,
|
|
to initialize and shutdown the connection-sharing module.
|
|
Initialization is minimal to keep down the performance hit incurred
|
|
on systems which make no use of the shared-access functionality.
|
|
|
|
Arguments:
|
|
|
|
Reason - indicates whether to initialize or shutdown.
|
|
|
|
Return Value:
|
|
|
|
BOOL - indicates success (TRUE) or failure (FALSE).
|
|
|
|
--*/
|
|
|
|
{
|
|
if (Reason == DLL_PROCESS_ATTACH) {
|
|
__try {
|
|
InitializeCriticalSection(&CsCriticalSection);
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return FALSE;
|
|
}
|
|
CsDllMainCalled = TRUE;
|
|
} else if (Reason == DLL_PROCESS_DETACH) {
|
|
if (!CsDllMainCalled) { return TRUE; }
|
|
__try {
|
|
EnterCriticalSection(&CsCriticalSection);
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return TRUE;
|
|
}
|
|
CsShutdownModule();
|
|
LeaveCriticalSection(&CsCriticalSection);
|
|
DeleteCriticalSection(&CsCriticalSection);
|
|
}
|
|
return TRUE;
|
|
} // DllMain
|
|
|
|
|
|
VOID
|
|
CsControlService(
|
|
ULONG ControlCode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to send a control-code to the Shared Access service
|
|
if it is active. Control-codes are used to indicate changes to the settings
|
|
for the service; see IPNATHLP.H for a list of private control-codes used
|
|
to indicate configuration changes.
|
|
|
|
Arguments:
|
|
|
|
ControlCode - the control to be sent.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
SC_HANDLE ScmHandle;
|
|
SC_HANDLE ServiceHandle;
|
|
SERVICE_STATUS ServiceStatus;
|
|
|
|
ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (ScmHandle) {
|
|
ServiceHandle =
|
|
OpenService(ScmHandle, c_szSharedAccess, SERVICE_ALL_ACCESS);
|
|
if (ServiceHandle) {
|
|
ControlService(ServiceHandle, ControlCode, &ServiceStatus);
|
|
CloseServiceHandle(ServiceHandle);
|
|
}
|
|
CloseServiceHandle(ScmHandle);
|
|
}
|
|
|
|
} // CsControlService
|
|
|
|
#if 0
|
|
|
|
|
|
ULONG
|
|
CsFirewallConnection(
|
|
LPRASSHARECONN Connection,
|
|
BOOLEAN Enable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to enable or disable the firewall on a connection.
|
|
|
|
Arguments:
|
|
|
|
Connection - the connection to [un]firewall
|
|
|
|
Enable - true if the firewall is to be enabled for this connection,
|
|
false if the firewall is to be disabled
|
|
|
|
Return Value:
|
|
|
|
Win32 Error code
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Count = 0;
|
|
ULONG Position;
|
|
LPRASSHARECONN ConnectionArray;
|
|
DWORD Error;
|
|
BOOLEAN IsFirewalled = FALSE;
|
|
|
|
//
|
|
// Query the number of currently firewalled connections, and
|
|
// retrieve the connection array if any exists.
|
|
//
|
|
|
|
Error = CsQueryFirewallConnections(NULL, &Count);
|
|
if (Error && Error != ERROR_INSUFFICIENT_BUFFER) {
|
|
return Error;
|
|
}
|
|
|
|
if (Count) {
|
|
ConnectionArray =
|
|
(LPRASSHARECONN) Malloc(Count * sizeof(RASSHARECONN));
|
|
|
|
if (!ConnectionArray) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Error = CsQueryFirewallConnections(ConnectionArray, &Count);
|
|
if (Error) {
|
|
Free(ConnectionArray);
|
|
return Error;
|
|
}
|
|
} else {
|
|
ConnectionArray = NULL;
|
|
}
|
|
|
|
//
|
|
// If there are firewalled connections, check to see if the connection
|
|
// passed in is one of them.
|
|
//
|
|
|
|
if (Count) {
|
|
IsFirewalled = CspIsConnectionFwWorker(
|
|
ConnectionArray,
|
|
Count,
|
|
Connection,
|
|
&Position
|
|
);
|
|
}
|
|
|
|
if (Enable) {
|
|
|
|
if (!IsFirewalled) {
|
|
Error = CspAddFirewallConnection(
|
|
Connection,
|
|
Count
|
|
);
|
|
|
|
if(ERROR_SUCCESS == Error) {
|
|
|
|
//
|
|
// Start (if needed) and update service. If the service
|
|
// is already running, CsStartService returns ERROR_SUCCESS.
|
|
//
|
|
|
|
if (0 == Count) {
|
|
Error = CsStartService();
|
|
}
|
|
CsControlService(IPNATHLP_CONTROL_UPDATE_CONNECTION);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Define ALREADY_ENABLED error?
|
|
//
|
|
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (IsFirewalled) {
|
|
Error = CspRemoveFirewallConnection(
|
|
Connection,
|
|
Position,
|
|
ConnectionArray,
|
|
Count
|
|
);
|
|
|
|
if (ERROR_SUCCESS == Error) {
|
|
|
|
//
|
|
// Stop or update service. We only stop the service if
|
|
// there is no shared connection, and this was the last
|
|
// firewalled connection (i.e., count was 10
|
|
//
|
|
|
|
RASSHARECONN SharedConn;
|
|
Error = CsQuerySharedConnection(&SharedConn);
|
|
|
|
if (ERROR_SUCCESS != Error && 1 == Count) {
|
|
CsStopService();
|
|
} else {
|
|
CsControlService(IPNATHLP_CONTROL_UPDATE_CONNECTION);
|
|
}
|
|
Error = ERROR_SUCCESS;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Define NOT_FIREWALLED error?
|
|
//
|
|
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
|
|
if (ConnectionArray) {
|
|
Free(ConnectionArray);
|
|
}
|
|
|
|
return Error;
|
|
} // CsFirewallConnection
|
|
|
|
#endif
|
|
|
|
|
|
ULONG
|
|
CsInitializeModule(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to initialize the connection-sharing configuration
|
|
module. Initialization consists of loading the entrypoints which we have
|
|
deferred loading up till now, in both MPRAPI.DLL and OLE32.DLL.
|
|
|
|
Arguments:
|
|
|
|
Instance - handle to the module-instance
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
HINSTANCE Hinstance;
|
|
EnterCriticalSection(&CsCriticalSection);
|
|
if (CsInitialized) {
|
|
Error = NO_ERROR;
|
|
} else {
|
|
if (!(CsOle32Dll = LoadLibraryW(c_szOle32Dll)) ||
|
|
!(g_pCoInitializeEx =
|
|
(PCOINITIALIZEEX)GetProcAddress(
|
|
CsOle32Dll, c_szCoInitializeEx
|
|
)) ||
|
|
!(g_pCoUninitialize =
|
|
(PCOUNINITIALIZE)GetProcAddress(
|
|
CsOle32Dll, c_szCoUninitialize
|
|
)) ||
|
|
!(g_pCoCreateInstance =
|
|
(PCOCREATEINSTANCE)GetProcAddress(
|
|
CsOle32Dll, c_szCoCreateInstance
|
|
)) ||
|
|
!(g_pCoSetProxyBlanket =
|
|
(PCOSETPROXYBLANKET)GetProcAddress(
|
|
CsOle32Dll, c_szCoSetProxyBlanket
|
|
)) ||
|
|
!(g_pCoTaskMemFree =
|
|
(PCOTASKMEMFREE)GetProcAddress(
|
|
CsOle32Dll, c_szCoTaskMemFree
|
|
))) {
|
|
if (CsOle32Dll) { FreeLibrary(CsOle32Dll); CsOle32Dll = NULL; }
|
|
TRACE1("CsInitializeModule: %d", GetLastError());
|
|
Error = ERROR_PROC_NOT_FOUND;
|
|
} else {
|
|
CsInitialized = TRUE;
|
|
Error = NO_ERROR;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&CsCriticalSection);
|
|
return Error;
|
|
|
|
} // CsInitializeModule
|
|
|
|
#if 0
|
|
|
|
|
|
ULONG
|
|
CsIsFirewalledConnection(
|
|
LPRASSHARECONN Connection,
|
|
PBOOLEAN Firewalled
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to determine if a connection is firewalled
|
|
|
|
Arguments:
|
|
|
|
Connection - the connection to check
|
|
|
|
Firewalled - receives the return value
|
|
|
|
Return Value:
|
|
|
|
ULONG - win32 error
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Count = 0;
|
|
LPRASSHARECONN ConnectionArray;
|
|
ULONG Error;
|
|
|
|
if (!Firewalled) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
*Firewalled = FALSE;
|
|
|
|
Error = CsQueryFirewallConnections(NULL, &Count);
|
|
if (Error && Error != ERROR_INSUFFICIENT_BUFFER) {
|
|
return Error;
|
|
}
|
|
|
|
ConnectionArray =
|
|
(LPRASSHARECONN) Malloc(Count * sizeof(RASSHARECONN));
|
|
|
|
if (!ConnectionArray) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Error = CsQueryFirewallConnections(ConnectionArray, &Count);
|
|
if (Error) {
|
|
Free(ConnectionArray);
|
|
return Error;
|
|
}
|
|
|
|
*Firewalled = CspIsConnectionFwWorker(ConnectionArray, Count, Connection, NULL);
|
|
Free(ConnectionArray);
|
|
return NO_ERROR;
|
|
} // CsIsConnectionFirewalled
|
|
|
|
|
|
BOOLEAN
|
|
CsIsRoutingProtocolInstalled(
|
|
ULONG ProtocolId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to determine whether the routing protocol
|
|
with the given protocol-ID is installed for Routing and Remote Access.
|
|
This is determined by examining the configuration for the service.
|
|
|
|
Arguments:
|
|
|
|
ProtocolId - identifies the protocol to be found
|
|
|
|
Return Value:
|
|
|
|
TRUE if the protocol is installed, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR Buffer;
|
|
ULONG BufferLength;
|
|
HINSTANCE Hinstance;
|
|
PMPRCONFIGBUFFERFREE MprConfigBufferFree;
|
|
PMPRCONFIGSERVERCONNECT MprConfigServerConnect;
|
|
PMPRCONFIGSERVERDISCONNECT MprConfigServerDisconnect;
|
|
PMPRCONFIGTRANSPORTGETHANDLE MprConfigTransportGetHandle;
|
|
PMPRCONFIGTRANSPORTGETINFO MprConfigTransportGetInfo;
|
|
PMPRINFOBLOCKFIND MprInfoBlockFind;
|
|
HANDLE ServerHandle;
|
|
HANDLE TransportHandle;
|
|
|
|
//
|
|
// Load the MPRAPI.DLL module and retrieve the entrypoints
|
|
// to be used for examining the RRAS configuration.
|
|
//
|
|
|
|
if (!(Hinstance = LoadLibraryW(c_szMprapiDll)) ||
|
|
!(MprConfigBufferFree =
|
|
(PMPRCONFIGBUFFERFREE)
|
|
GetProcAddress(Hinstance, c_szMprConfigBufferFree)) ||
|
|
!(MprConfigServerConnect =
|
|
(PMPRCONFIGSERVERCONNECT)
|
|
GetProcAddress(Hinstance, c_szMprConfigServerConnect)) ||
|
|
!(MprConfigServerDisconnect =
|
|
(PMPRCONFIGSERVERDISCONNECT)
|
|
GetProcAddress(Hinstance, c_szMprConfigServerDisconnect)) ||
|
|
!(MprConfigTransportGetHandle =
|
|
(PMPRCONFIGTRANSPORTGETHANDLE)
|
|
GetProcAddress(Hinstance, c_szMprConfigTransportGetHandle)) ||
|
|
!(MprConfigTransportGetInfo =
|
|
(PMPRCONFIGTRANSPORTGETINFO)
|
|
GetProcAddress(Hinstance, c_szMprConfigTransportGetInfo)) ||
|
|
!(MprInfoBlockFind =
|
|
(PMPRINFOBLOCKFIND)
|
|
GetProcAddress(Hinstance, c_szMprInfoBlockFind))) {
|
|
if (Hinstance) { FreeLibrary(Hinstance); }
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Connect to the RRAS configuration, and retrieve the configuration
|
|
// for the IP transport-layer routing protocols. This should include
|
|
// the configuration for the routing-protocol in 'ProtocolId',
|
|
// if installed.
|
|
//
|
|
|
|
ServerHandle = NULL;
|
|
if (MprConfigServerConnect(NULL, &ServerHandle) != NO_ERROR ||
|
|
MprConfigTransportGetHandle(ServerHandle, PID_IP, &TransportHandle)
|
|
!= NO_ERROR ||
|
|
MprConfigTransportGetInfo(
|
|
ServerHandle,
|
|
TransportHandle,
|
|
&Buffer,
|
|
&BufferLength,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
) != NO_ERROR) {
|
|
if (ServerHandle) { MprConfigServerDisconnect(ServerHandle); }
|
|
FreeLibrary(Hinstance);
|
|
return FALSE;
|
|
}
|
|
|
|
MprConfigServerDisconnect(ServerHandle);
|
|
|
|
//
|
|
// Look for the requested protocol's configuration,
|
|
// and return TRUE if it is found; otherwise, return FALSE.
|
|
//
|
|
|
|
if (MprInfoBlockFind(Buffer, ProtocolId, NULL, NULL, NULL) == NO_ERROR) {
|
|
MprConfigBufferFree(Buffer);
|
|
FreeLibrary(Hinstance);
|
|
return TRUE;
|
|
}
|
|
MprConfigBufferFree(Buffer);
|
|
FreeLibrary(Hinstance);
|
|
return FALSE;
|
|
} // CsIsRoutingProtocolInstalled
|
|
|
|
#endif
|
|
|
|
|
|
ULONG
|
|
CsIsSharedConnection(
|
|
LPRASSHARECONN Connection,
|
|
PBOOLEAN Shared
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to determine whether the given connection
|
|
is the currently-shared connection.
|
|
|
|
For added performance, this may be changed to cache the shared-connection
|
|
and use registry change-notification to detect updates.
|
|
|
|
Arguments:
|
|
|
|
Connection - the connection in question
|
|
|
|
Shared - receives 'TRUE' if the 'Name' is the shared connection,
|
|
and 'FALSE' otherwise
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
Environment:
|
|
|
|
This routine is called *without* initializing the module
|
|
(i.e. loading mprapi.dll and ole32.dll), for performance reasons.
|
|
Hence, it may not invoke any mprapi.dll routines.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
RASSHARECONN SharedConnection;
|
|
if (Shared) {
|
|
Error = CsQuerySharedConnection(&SharedConnection);
|
|
if (Error) {
|
|
*Shared = FALSE;
|
|
} else {
|
|
*Shared = RasIsEqualSharedConnection(Connection, &SharedConnection);
|
|
}
|
|
}
|
|
return NO_ERROR;
|
|
} // CsIsSharedConnection
|
|
|
|
#if 0
|
|
|
|
|
|
ULONG
|
|
CsMapGuidToAdapterIndex(
|
|
PWCHAR Guid,
|
|
PGETINTERFACEINFO GetInterfaceInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to match the GUID in the given string to
|
|
an adapter in the list returned by calling the given entrypoint.
|
|
|
|
Arguments:
|
|
|
|
Guid - identifies the GUID of the adapter to be found
|
|
|
|
GetInterfaceInfo - supplies GUID information for each adapter
|
|
|
|
Return Value:
|
|
|
|
ULONG - the index of the adapter, if found; otherwise, -1.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG AdapterIndex = (ULONG)-1;
|
|
ULONG i;
|
|
ULONG GuidLength;
|
|
PIP_INTERFACE_INFO Info;
|
|
PWCHAR Name;
|
|
ULONG NameLength;
|
|
ULONG Size;
|
|
Size = 0;
|
|
GuidLength = lstrlenW(Guid);
|
|
if (GetInterfaceInfo(NULL, &Size) == ERROR_INSUFFICIENT_BUFFER) {
|
|
Info = Malloc(Size);
|
|
if (Info) {
|
|
if (GetInterfaceInfo(Info, &Size) == NO_ERROR) {
|
|
for (i = 0; i < (ULONG)Info->NumAdapters; i++) {
|
|
NameLength = lstrlenW(Info->Adapter[i].Name);
|
|
if (NameLength < GuidLength) { continue; }
|
|
Name = Info->Adapter[i].Name + (NameLength - GuidLength);
|
|
if (lstrcmpiW(Guid, Name) == 0) {
|
|
AdapterIndex = Info->Adapter[i].Index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Free(Info);
|
|
}
|
|
}
|
|
return AdapterIndex;
|
|
} // CsMapGuidToAdapter
|
|
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
CsOpenKey(
|
|
PHANDLE Key,
|
|
ACCESS_MASK DesiredAccess,
|
|
PCWSTR Name
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to open a given registry key.
|
|
|
|
Arguments:
|
|
|
|
Key - receives the opened key
|
|
|
|
DesiredAccess - specifies the requested access
|
|
|
|
Name - specifies the key to be opened
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - NT status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
RtlInitUnicodeString(&UnicodeString, Name);
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
return NtOpenKey(Key, DesiredAccess, &ObjectAttributes);
|
|
} // CsOpenKey
|
|
|
|
#if 0
|
|
|
|
|
|
ULONG
|
|
CspAddFirewallConnection(
|
|
LPRASSHARECONN Connection,
|
|
ULONG Number
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to add a connection to the registry set.
|
|
|
|
Arguments:
|
|
|
|
Connection - the connection to add
|
|
|
|
Number - the number of this connection
|
|
|
|
Return Value:
|
|
|
|
Win32 error code
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE Key;
|
|
UNICODE_STRING ValueName;
|
|
ULONG Count;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// +11 is enough room to hold the digits of a number >4,000,000,000, so
|
|
// buffer overflow won't be an issue below.
|
|
//
|
|
|
|
WCHAR wsz[sizeof(c_szFirewallConnection)/sizeof(WCHAR) + 11];
|
|
|
|
//
|
|
// Open the key to SharedAccess/Parameters
|
|
//
|
|
|
|
Status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return RtlNtStatusToDosError(Status);
|
|
}
|
|
|
|
//
|
|
// Generate the string for the connection value
|
|
//
|
|
|
|
swprintf(wsz, L"%s%u", c_szFirewallConnection, Number);
|
|
RtlInitUnicodeString(&ValueName, wsz);
|
|
|
|
//
|
|
// Write the connection to the registry
|
|
//
|
|
|
|
Status = NtSetValueKey(
|
|
Key,
|
|
&ValueName,
|
|
0,
|
|
REG_BINARY,
|
|
Connection,
|
|
Connection->dwSize
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
NtClose(Key);
|
|
return RtlNtStatusToDosError(Status);
|
|
}
|
|
|
|
//
|
|
// Write the updated count to the registry
|
|
//
|
|
|
|
RtlInitUnicodeString(&ValueName, c_szFirewallConnectionCount);
|
|
Count = Number + 1; // number is 0 indexed
|
|
|
|
Status = NtSetValueKey(
|
|
Key,
|
|
&ValueName,
|
|
0,
|
|
REG_DWORD,
|
|
&Count,
|
|
sizeof(DWORD)
|
|
);
|
|
|
|
NtClose(Key);
|
|
return RtlNtStatusToDosError(Status);
|
|
} // CspAddFirewallConnection
|
|
|
|
|
|
VOID
|
|
CspBackupAddressInformation(
|
|
HANDLE Key,
|
|
PCS_ADDRESS_INFORMATION Information
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING UnicodeString;
|
|
do {
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupIPAddress);
|
|
status =
|
|
NtSetValueKey(
|
|
Key,
|
|
&UnicodeString,
|
|
0,
|
|
Information->IPAddress->Type,
|
|
Information->IPAddress->Data,
|
|
Information->IPAddress->DataLength
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupSubnetMask);
|
|
status =
|
|
NtSetValueKey(
|
|
Key,
|
|
&UnicodeString,
|
|
0,
|
|
Information->SubnetMask->Type,
|
|
Information->SubnetMask->Data,
|
|
Information->SubnetMask->DataLength
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupDefaultGateway);
|
|
status =
|
|
NtSetValueKey(
|
|
Key,
|
|
&UnicodeString,
|
|
0,
|
|
Information->DefaultGateway->Type,
|
|
Information->DefaultGateway->Data,
|
|
Information->DefaultGateway->DataLength
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupEnableDHCP);
|
|
status =
|
|
NtSetValueKey(
|
|
Key,
|
|
&UnicodeString,
|
|
0,
|
|
Information->EnableDHCP->Type,
|
|
Information->EnableDHCP->Data,
|
|
Information->EnableDHCP->DataLength
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
return;
|
|
} while(FALSE);
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupIPAddress);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupSubnetMask);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupDefaultGateway);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupEnableDHCP);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
} // CspBackupAddressInformation
|
|
|
|
|
|
NTSTATUS
|
|
CspCaptureAddressInformation(
|
|
PWCHAR AdapterGuid,
|
|
PCS_ADDRESS_INFORMATION Information
|
|
)
|
|
{
|
|
HANDLE Key;
|
|
PWCHAR KeyName;
|
|
ULONG KeyNameLength;
|
|
NTSTATUS status;
|
|
|
|
KeyNameLength =
|
|
sizeof(WCHAR) *
|
|
(lstrlenW(c_szTcpipParametersKey) + 1 +
|
|
lstrlenW(c_szInterfaces) + 1 +
|
|
lstrlenW(AdapterGuid) + 2);
|
|
if (!(KeyName = Malloc(KeyNameLength))) { return STATUS_NO_MEMORY; }
|
|
|
|
wsprintfW(
|
|
KeyName, L"%ls\\%ls\\%ls", c_szTcpipParametersKey, c_szInterfaces,
|
|
AdapterGuid
|
|
);
|
|
status = CsOpenKey(&Key, KEY_READ, KeyName);
|
|
Free(KeyName);
|
|
if (!NT_SUCCESS(status)) { return status; }
|
|
|
|
do {
|
|
status =
|
|
CsQueryValueKey(
|
|
Key, c_szIPAddress, &Information->IPAddress
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
status =
|
|
CsQueryValueKey(
|
|
Key, c_szSubnetMask, &Information->SubnetMask
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
status =
|
|
CsQueryValueKey(
|
|
Key, c_szDefaultGateway, &Information->DefaultGateway
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
status =
|
|
CsQueryValueKey(
|
|
Key, c_szEnableDHCP, &Information->EnableDHCP
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
} while(FALSE);
|
|
|
|
NtClose(Key);
|
|
return status;
|
|
} // CspCaptureAddressInformation
|
|
|
|
|
|
VOID
|
|
CspCleanupAddressInformation(
|
|
PCS_ADDRESS_INFORMATION Information
|
|
)
|
|
{
|
|
Free0(Information->IPAddress);
|
|
Free0(Information->SubnetMask);
|
|
Free0(Information->DefaultGateway);
|
|
Free0(Information->EnableDHCP);
|
|
} // CspCleanupAddressInformation
|
|
|
|
|
|
ULONG
|
|
CspRemoveFirewallConnection(
|
|
LPRASSHARECONN Connection,
|
|
ULONG Position,
|
|
LPRASSHARECONN ConnectionArray,
|
|
ULONG Count
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to remove a connection to the registry set.
|
|
|
|
Arguments:
|
|
|
|
Connection - the connection to remove
|
|
|
|
Number - its index in ConnectionArray
|
|
|
|
ConnectionArray - currently firewalled connections
|
|
|
|
Count - the number of entries in ConnectionArray
|
|
|
|
Return Value:
|
|
|
|
Win32 error code
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE Key;
|
|
UNICODE_STRING ValueName;
|
|
ULONG i;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// +11 is enough room to hold the digits of a number >4,000,000,000, so
|
|
// buffer overflow won't be an issue below.
|
|
//
|
|
|
|
WCHAR wsz[sizeof(c_szFirewallConnection)/sizeof(WCHAR) + 11];
|
|
|
|
//
|
|
// Open the key to IPFirewall/Parameters
|
|
//
|
|
|
|
Status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return RtlNtStatusToDosError(Status);
|
|
}
|
|
|
|
//
|
|
// Shift entries above the connection we're removing down one
|
|
// (overwriting the entry we want to remove)
|
|
//
|
|
|
|
for (i = Position + 1; i < Count; i++) {
|
|
|
|
//
|
|
// Generate key name for previous entry
|
|
//
|
|
|
|
swprintf(wsz, L"%s%u", c_szFirewallConnection, i - 1);
|
|
RtlInitUnicodeString(&ValueName, wsz);
|
|
|
|
//
|
|
// Write current entry into previous slot
|
|
//
|
|
|
|
Status = NtSetValueKey(
|
|
Key,
|
|
&ValueName,
|
|
0,
|
|
REG_BINARY,
|
|
&ConnectionArray[i],
|
|
ConnectionArray[i].dwSize
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
NtClose(Key);
|
|
return RtlNtStatusToDosError(Status);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete the last entry. This is either the entry we want to
|
|
// remove (if it was the last entry to begin with), or an entry
|
|
// that has already been duplicated into the previous position.
|
|
//
|
|
|
|
swprintf(wsz, L"%s%u", c_szFirewallConnection, Count - 1);
|
|
RtlInitUnicodeString(&ValueName, wsz);
|
|
|
|
Status = NtDeleteValueKey(Key, &ValueName);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
NtClose(Key);
|
|
return RtlNtStatusToDosError(Status);
|
|
}
|
|
|
|
|
|
//
|
|
// Store the decremented count in the registry
|
|
//
|
|
|
|
RtlInitUnicodeString(&ValueName, c_szFirewallConnectionCount);
|
|
i = Count - 1;
|
|
|
|
Status = NtSetValueKey(
|
|
Key,
|
|
&ValueName,
|
|
0,
|
|
REG_DWORD,
|
|
&i,
|
|
sizeof(DWORD)
|
|
);
|
|
|
|
|
|
NtClose(Key);
|
|
return RtlNtStatusToDosError(Status);
|
|
} // CspRemoveFirewallConnection
|
|
|
|
|
|
|
|
ULONG
|
|
CsQueryFirewallConnections(
|
|
LPRASSHARECONN ConnectionArray,
|
|
ULONG *ConnectionCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to retrieve the firewalled connections, if any.
|
|
|
|
Arguments:
|
|
|
|
ConnectionArray - receives the retrieved connections.
|
|
|
|
ConnectionCount - in: how many entries the array can hold
|
|
out: number of entries returned, or the needed
|
|
size of the array (for ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE Key;
|
|
PKEY_VALUE_PARTIAL_INFORMATION Information;
|
|
NTSTATUS Status;
|
|
ULONG Count;
|
|
ULONG i;
|
|
|
|
if (!ConnectionCount) { return ERROR_INVALID_PARAMETER; }
|
|
if (*ConnectionCount && !ConnectionArray) {
|
|
//
|
|
// It's OK to pass in NULL for the array if just trying
|
|
// to determine what size buffer to use
|
|
//
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Open the 'SharedAccess\Parameters' key,
|
|
// and read the 'FirewallConnectionCount' value
|
|
//
|
|
|
|
Status = CsOpenKey(&Key, KEY_READ, c_szSharedAccessParametersKey);
|
|
if (!NT_SUCCESS(Status)) {
|
|
TRACE1(
|
|
"CsQueryFirewallConnections: CsOpenKey=%x", Status
|
|
);
|
|
return RtlNtStatusToDosError(Status);
|
|
}
|
|
|
|
Status = CsQueryValueKey(Key, c_szFirewallConnectionCount, &Information);
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Validate the information, and check to see if the passed in array
|
|
// is sufficient in size.
|
|
//
|
|
|
|
if (Information->DataLength != sizeof(DWORD) ||
|
|
Information->Type != REG_DWORD) {
|
|
|
|
TRACE(
|
|
"CsQueryFirewallConnections: invalid data in registry for count"
|
|
);
|
|
NtClose(Key);
|
|
Free(Information);
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
Count = (ULONG) *Information->Data;
|
|
Free(Information);
|
|
|
|
} else {
|
|
Count = 0;
|
|
}
|
|
|
|
if (*ConnectionCount < Count) {
|
|
//
|
|
// Too many entries for the passed in buffer
|
|
//
|
|
|
|
NtClose(Key);
|
|
*ConnectionCount = Count;
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*ConnectionCount = Count;
|
|
|
|
//
|
|
// Read all of the connection entries from the registry.
|
|
//
|
|
|
|
for(i = 0; i < Count; i++) {
|
|
WCHAR wsz[sizeof(c_szFirewallConnection)/sizeof(WCHAR) + 11];
|
|
|
|
swprintf(wsz, L"%s%u", c_szFirewallConnection, i);
|
|
Status = CsQueryValueKey(Key, wsz, &Information);
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(Key);
|
|
return RtlNtStatusToDosError(Status);
|
|
}
|
|
|
|
//
|
|
// Validate the retrieved information,
|
|
// and copy it to the given buffer
|
|
//
|
|
|
|
if (Information->DataLength != sizeof(RASSHARECONN) ||
|
|
((LPRASSHARECONN)Information->Data)->dwSize != sizeof(RASSHARECONN)) {
|
|
|
|
TRACE2(
|
|
"CsQueryFirewallConnections: invalid length %d (size=%d) in registry",
|
|
Information->DataLength,
|
|
((LPRASSHARECONN)Information->Data)->dwSize
|
|
);
|
|
|
|
Free(Information);
|
|
NtClose(Key);
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
CopyMemory(&ConnectionArray[i], Information->Data, sizeof(RASSHARECONN));
|
|
Free(Information);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // CsQueryFirewallConnections
|
|
|
|
|
|
BOOLEAN
|
|
CspIsConnectionFwWorker(
|
|
LPRASSHARECONN ConnectionArray,
|
|
ULONG Count,
|
|
LPRASSHARECONN Connection,
|
|
ULONG *Position OUT OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to determine if a connection is firewalled
|
|
|
|
Arguments:
|
|
|
|
ConnectionArray - Buffer containing currently FWd connections
|
|
|
|
Count - number of connections in the array
|
|
|
|
Connection - the connection to check
|
|
|
|
Position - receives the number of the connection, if found (undefined otherwise)
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN -- true if the passed in connection is currently firewalled
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < Count; i++) {
|
|
if (RasIsEqualSharedConnection(Connection, &ConnectionArray[i])) {
|
|
if (Position) *Position = i;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
} // FwpIsConnectionFwWorker
|
|
|
|
|
|
NTSTATUS
|
|
CspRestoreAddressInformation(
|
|
HANDLE Key,
|
|
PWCHAR AdapterGuid
|
|
)
|
|
{
|
|
HANDLE AdapterKey = NULL;
|
|
PWCHAR AdapterKeyName = NULL;
|
|
PDHCPNOTIFYCONFIGCHANGE DhcpNotifyConfigChange;
|
|
ULONG Error;
|
|
HINSTANCE Hinstance;
|
|
CS_ADDRESS_INFORMATION Information;
|
|
ULONG Length;
|
|
NTSTATUS status;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
if (!(Hinstance = LoadLibraryW(c_szDhcpcsvcDll)) ||
|
|
!(DhcpNotifyConfigChange =
|
|
(PDHCPNOTIFYCONFIGCHANGE)
|
|
GetProcAddress(
|
|
Hinstance, c_szDhcpNotifyConfigChange
|
|
))) {
|
|
if (Hinstance) { FreeLibrary(Hinstance); }
|
|
return ERROR_PROC_NOT_FOUND;
|
|
}
|
|
|
|
do {
|
|
|
|
ZeroMemory(&Information, sizeof(Information));
|
|
status =
|
|
CsQueryValueKey(
|
|
Key, c_szBackupIPAddress, &Information.IPAddress
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
status =
|
|
CsQueryValueKey(
|
|
Key, c_szBackupSubnetMask, &Information.SubnetMask
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
status =
|
|
CsQueryValueKey(
|
|
Key, c_szBackupDefaultGateway, &Information.DefaultGateway
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
status =
|
|
CsQueryValueKey(
|
|
Key, c_szBackupEnableDHCP, &Information.EnableDHCP
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
|
|
Length =
|
|
sizeof(WCHAR) *
|
|
(lstrlenW(c_szTcpipParametersKey) + 1 +
|
|
lstrlenW(c_szInterfaces) + 1 +
|
|
lstrlenW(AdapterGuid) + 2);
|
|
if (!(AdapterKeyName = Malloc(Length))) {
|
|
status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
|
|
wsprintfW(
|
|
AdapterKeyName, L"%ls\\%ls\\%ls", c_szTcpipParametersKey,
|
|
c_szInterfaces, AdapterGuid
|
|
);
|
|
status = CsOpenKey(&AdapterKey, KEY_ALL_ACCESS, AdapterKeyName);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
|
|
RtlInitUnicodeString(&UnicodeString, c_szIPAddress);
|
|
status =
|
|
NtSetValueKey(
|
|
AdapterKey,
|
|
&UnicodeString,
|
|
0,
|
|
Information.IPAddress->Type,
|
|
Information.IPAddress->Data,
|
|
Information.IPAddress->DataLength
|
|
);
|
|
RtlInitUnicodeString(&UnicodeString, c_szSubnetMask);
|
|
status =
|
|
NtSetValueKey(
|
|
AdapterKey,
|
|
&UnicodeString,
|
|
0,
|
|
Information.SubnetMask->Type,
|
|
Information.SubnetMask->Data,
|
|
Information.SubnetMask->DataLength
|
|
);
|
|
RtlInitUnicodeString(&UnicodeString, c_szDefaultGateway);
|
|
status =
|
|
NtSetValueKey(
|
|
AdapterKey,
|
|
&UnicodeString,
|
|
0,
|
|
Information.DefaultGateway->Type,
|
|
Information.DefaultGateway->Data,
|
|
Information.DefaultGateway->DataLength
|
|
);
|
|
RtlInitUnicodeString(&UnicodeString, c_szEnableDHCP);
|
|
status =
|
|
NtSetValueKey(
|
|
AdapterKey,
|
|
&UnicodeString,
|
|
0,
|
|
Information.EnableDHCP->Type,
|
|
Information.EnableDHCP->Data,
|
|
Information.EnableDHCP->DataLength
|
|
);
|
|
if (!NT_SUCCESS(status)) { break; }
|
|
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupIPAddress);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupSubnetMask);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupDefaultGateway);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
RtlInitUnicodeString(&UnicodeString, c_szBackupEnableDHCP);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
|
|
if (*(PULONG)Information.EnableDHCP->Data) {
|
|
Error =
|
|
DhcpNotifyConfigChange(
|
|
NULL,
|
|
AdapterGuid,
|
|
FALSE,
|
|
0,
|
|
0,
|
|
0,
|
|
DhcpEnable
|
|
);
|
|
} else {
|
|
|
|
ULONG Address;
|
|
UNICODE_STRING BindList;
|
|
UNICODE_STRING LowerComponent;
|
|
ULONG Mask;
|
|
IP_PNP_RECONFIG_REQUEST Request;
|
|
UNICODE_STRING UpperComponent;
|
|
|
|
Address = IpPszToHostAddr((PWCHAR)Information.IPAddress->Data);
|
|
if (Address) {
|
|
Address = RtlUlongByteSwap(Address);
|
|
Mask = IpPszToHostAddr((PWCHAR)Information.SubnetMask->Data);
|
|
if (Mask) {
|
|
Mask = RtlUlongByteSwap(Mask);
|
|
Error =
|
|
DhcpNotifyConfigChange(
|
|
NULL,
|
|
AdapterGuid,
|
|
TRUE,
|
|
0,
|
|
Address,
|
|
Mask,
|
|
DhcpDisable
|
|
);
|
|
}
|
|
}
|
|
|
|
RtlInitUnicodeString(&BindList, c_szEmpty);
|
|
RtlInitUnicodeString(&LowerComponent, c_szEmpty);
|
|
RtlInitUnicodeString(&UpperComponent, c_szTcpip);
|
|
ZeroMemory(&Request, sizeof(Request));
|
|
Request.version = IP_PNP_RECONFIG_VERSION;
|
|
Request.gatewayListUpdate = TRUE;
|
|
Request.Flags = IP_PNP_FLAG_GATEWAY_LIST_UPDATE;
|
|
status =
|
|
NdisHandlePnPEvent(
|
|
NDIS,
|
|
RECONFIGURE,
|
|
&LowerComponent,
|
|
&UpperComponent,
|
|
&BindList,
|
|
&Request,
|
|
sizeof(Request)
|
|
);
|
|
}
|
|
} while(FALSE);
|
|
if (AdapterKey) { NtClose(AdapterKey); }
|
|
Free0(AdapterKeyName);
|
|
CspCleanupAddressInformation(&Information);
|
|
FreeLibrary(Hinstance);
|
|
return status;
|
|
} // CspRestoreAddressInformation
|
|
|
|
|
|
ULONG
|
|
CsQueryLanConnTable(
|
|
LPRASSHARECONN ExcludedConnection,
|
|
NETCON_PROPERTIES** LanConnTable,
|
|
LPDWORD LanConnCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to retrieve an array of LAN connections,
|
|
discounting 'ExcludeConnection', which will typically be the name
|
|
of the public interface.
|
|
|
|
Arguments:
|
|
|
|
ExcludeConnection - a connection not allowed to be the private connection
|
|
|
|
LanConnTable - optionally receives a table of possible private networks.
|
|
|
|
LanConnCount - receives a count of the possible private networks.
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN CleanupOle = TRUE;
|
|
INetConnection* ConArray[32];
|
|
ULONG ConCount;
|
|
INetConnectionManager* ConMan = NULL;
|
|
IEnumNetConnection* EnumCon = NULL;
|
|
ULONG Error;
|
|
HRESULT hr;
|
|
ULONG i;
|
|
ULONG j;
|
|
ULONG LanCount = 0;
|
|
NETCON_PROPERTIES* LanProps = NULL;
|
|
NETCON_PROPERTIES* LanTable = NULL;
|
|
BSTR Name;
|
|
NETCON_STATUS ncs;
|
|
NTSTATUS status;
|
|
ULONG Size;
|
|
NETCON_MEDIATYPE MediaType;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
*LanConnCount = 0;
|
|
if (LanConnTable) { *LanConnTable = NULL; }
|
|
|
|
hr = g_pCoInitializeEx(NULL, COINIT_MULTITHREADED|COINIT_DISABLE_OLE1DDE);
|
|
if (!SUCCEEDED(hr)) {
|
|
if (hr == RPC_E_CHANGED_MODE) {
|
|
CleanupOle = FALSE;
|
|
} else {
|
|
TRACE1("CsQueryLanConnTable: CoInitializeEx=%x", hr);
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
Error = NO_ERROR;
|
|
|
|
do {
|
|
|
|
//
|
|
// Instantiate the connection manager
|
|
//
|
|
|
|
hr =
|
|
g_pCoCreateInstance(
|
|
&CLSID_ConnectionManager,
|
|
NULL,
|
|
CLSCTX_SERVER,
|
|
&IID_INetConnectionManager,
|
|
(PVOID*)&ConMan
|
|
);
|
|
if (!SUCCEEDED(hr)) {
|
|
TRACE1("CsQueryLanConnTable: CoCreateInstance=%x", hr);
|
|
ConMan = NULL; break;
|
|
}
|
|
|
|
//
|
|
// Instantiate a connection-enumerator
|
|
//
|
|
|
|
hr =
|
|
INetConnectionManager_EnumConnections(
|
|
ConMan,
|
|
NCME_DEFAULT,
|
|
&EnumCon
|
|
);
|
|
if (!SUCCEEDED(hr)) {
|
|
TRACE1("CsQueryLanConnTable: EnumConnections=%x", hr);
|
|
EnumCon = NULL; break;
|
|
}
|
|
|
|
hr =
|
|
g_pCoSetProxyBlanket(
|
|
(IUnknown*)EnumCon,
|
|
RPC_C_AUTHN_WINNT,
|
|
RPC_C_AUTHN_NONE,
|
|
NULL,
|
|
RPC_C_AUTHN_LEVEL_CALL,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL,
|
|
EOAC_NONE
|
|
);
|
|
|
|
//
|
|
// Enumerate the items
|
|
//
|
|
|
|
for ( ; ; ) {
|
|
|
|
hr =
|
|
IEnumNetConnection_Next(
|
|
EnumCon,
|
|
Dimension(ConArray),
|
|
ConArray,
|
|
&ConCount
|
|
);
|
|
if (!SUCCEEDED(hr) || !ConCount) { hr = S_OK; break; }
|
|
|
|
if (LanConnTable) {
|
|
|
|
//
|
|
// Allocate or reallocate the memory for storing
|
|
// connections which we will return to the caller.
|
|
//
|
|
|
|
if (!LanTable) {
|
|
LanTable =
|
|
(NETCON_PROPERTIES*)
|
|
GlobalAlloc(
|
|
0,
|
|
ConCount * sizeof(NETCON_PROPERTIES)
|
|
);
|
|
} else {
|
|
PVOID Temp =
|
|
GlobalAlloc(
|
|
0,
|
|
(LanCount + ConCount) * sizeof(NETCON_PROPERTIES)
|
|
);
|
|
if (Temp) {
|
|
CopyMemory(
|
|
Temp,
|
|
LanTable,
|
|
LanCount * sizeof(NETCON_PROPERTIES)
|
|
);
|
|
}
|
|
GlobalFree(LanTable);
|
|
LanTable = Temp;
|
|
}
|
|
|
|
if (!LanTable) { Error = ERROR_NOT_ENOUGH_MEMORY; break; }
|
|
}
|
|
|
|
LanCount += ConCount;
|
|
|
|
//
|
|
// Examine the properties for the connections retrieved
|
|
//
|
|
|
|
for (j = 0; j < ConCount; j++) {
|
|
|
|
hr = INetConnection_GetProperties(ConArray[j], &LanProps);
|
|
INetConnection_Release(ConArray[j]);
|
|
|
|
if (SUCCEEDED(hr) &&
|
|
LanProps->MediaType == NCM_LAN &&
|
|
(!ExcludedConnection->fIsLanConnection ||
|
|
!IsEqualGUID(
|
|
&ExcludedConnection->guid, &LanProps->guidId))) {
|
|
|
|
//
|
|
// This connection qualifies to be private; copy it.
|
|
//
|
|
|
|
if (!LanConnTable) {
|
|
++i;
|
|
} else {
|
|
LanTable[i] = *LanProps;
|
|
LanTable[i].pszwName = StrDupW(LanProps->pszwName);
|
|
LanTable[i].pszwDeviceName =
|
|
StrDupW(LanProps->pszwDeviceName);
|
|
if (LanTable[i].pszwName &&
|
|
LanTable[i].pszwDeviceName
|
|
) {
|
|
++i;
|
|
} else {
|
|
Free0(LanTable[i].pszwName);
|
|
Free0(LanTable[i].pszwDeviceName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (LanProps) {
|
|
g_pCoTaskMemFree(LanProps->pszwName);
|
|
g_pCoTaskMemFree(LanProps->pszwDeviceName);
|
|
g_pCoTaskMemFree(LanProps);
|
|
LanProps = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (EnumCon) { IEnumNetConnection_Release(EnumCon); }
|
|
if (ConMan) { INetConnectionManager_Release(ConMan); }
|
|
if (CleanupOle) { g_pCoUninitialize(); }
|
|
|
|
if (LanConnTable) { *LanConnTable = LanTable; }
|
|
*LanConnCount = i;
|
|
|
|
return Error;
|
|
|
|
} // CsQueryLanConnTable
|
|
|
|
|
|
VOID
|
|
CsQueryScopeInformation(
|
|
IN OUT PHANDLE Key,
|
|
PULONG Address,
|
|
PULONG Mask
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to retrieve the private network address and mask
|
|
to be used for shared access. If no value is found, the default
|
|
is supplied.
|
|
|
|
Arguments:
|
|
|
|
Key - optionally supplies an open handle to the SharedAccess\Parameters
|
|
registry key
|
|
|
|
Address - receives the address for the private network,
|
|
in network byte order
|
|
|
|
Mask - receives the mask for the private network, in network byte order
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
PKEY_VALUE_PARTIAL_INFORMATION Information;
|
|
HANDLE LocalKey = NULL;
|
|
NTSTATUS status;
|
|
|
|
if (!Key) { Key = &LocalKey; }
|
|
if (*Key) {
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = CsOpenKey(Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
status = CsQueryValueKey(*Key, c_szScopeAddress, &Information);
|
|
if (NT_SUCCESS(status)) {
|
|
if (!(*Address = IpPszToHostAddr((PWCHAR)Information->Data))) {
|
|
Free(Information);
|
|
} else {
|
|
Free(Information);
|
|
status = CsQueryValueKey(*Key, c_szScopeMask, &Information);
|
|
if (NT_SUCCESS(status)) {
|
|
if (!(*Mask = IpPszToHostAddr((PWCHAR)Information->Data))) {
|
|
Free(Information);
|
|
} else {
|
|
Free(Information);
|
|
*Address = RtlUlongByteSwap(*Address);
|
|
*Mask = RtlUlongByteSwap(*Mask);
|
|
if (LocalKey) { NtClose(LocalKey); }
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*Address = DEFAULT_SCOPE_ADDRESS;
|
|
*Mask = DEFAULT_SCOPE_MASK;
|
|
if (LocalKey) { NtClose(LocalKey); }
|
|
|
|
} // CsQueryScopeInformation
|
|
|
|
#endif
|
|
|
|
|
|
ULONG
|
|
CsQuerySharedConnection(
|
|
LPRASSHARECONN Connection
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to retrieve the shared connection, if any.
|
|
|
|
Arguments:
|
|
|
|
Connection - receives the retrieved connection.
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL fUninitializeCOM = TRUE;
|
|
IHNetIcsSettings *pIcsSettings;
|
|
IEnumHNetIcsPublicConnections *pEnumIcsPub;
|
|
IHNetIcsPublicConnection *pIcsPub;
|
|
IHNetConnection *pConn;
|
|
ULONG ulCount;
|
|
HRESULT hr;
|
|
|
|
ASSERT(NULL != g_pCoInitializeEx);
|
|
ASSERT(NULL != g_pCoCreateInstance);
|
|
ASSERT(NULL != g_pCoUninitialize);
|
|
|
|
if (!Connection) { return ERROR_INVALID_PARAMETER; }
|
|
|
|
hr = g_pCoInitializeEx(
|
|
NULL,
|
|
COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
fUninitializeCOM = FALSE;
|
|
|
|
if(RPC_E_CHANGED_MODE == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = g_pCoCreateInstance(
|
|
&CLSID_HNetCfgMgr,
|
|
NULL,
|
|
CLSCTX_ALL,
|
|
&IID_IHNetIcsSettings,
|
|
(VOID**)&pIcsSettings
|
|
);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = IHNetIcsSettings_EnumIcsPublicConnections(
|
|
pIcsSettings,
|
|
&pEnumIcsPub
|
|
);
|
|
|
|
IHNetIcsSettings_Release(pIcsSettings);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = IEnumHNetIcsPublicConnections_Next(
|
|
pEnumIcsPub,
|
|
1,
|
|
&pIcsPub,
|
|
&ulCount
|
|
);
|
|
|
|
IEnumHNetIcsPublicConnections_Release(pEnumIcsPub);
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && 1 == ulCount)
|
|
{
|
|
hr = IHNetIcsPublicConnection_QueryInterface(
|
|
pIcsPub,
|
|
&IID_IHNetConnection,
|
|
(VOID**)&pConn
|
|
);
|
|
|
|
IHNetIcsPublicConnection_Release(pIcsPub);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HNET_CONN_PROPERTIES *pProps;
|
|
|
|
//
|
|
// Convert the IHNetConnection to a RASSHARECONN
|
|
//
|
|
|
|
hr = IHNetConnection_GetProperties(pConn, &pProps);
|
|
|
|
if (SUCCEEDED(hr) && pProps->fLanConnection)
|
|
{
|
|
GUID *pGuid;
|
|
|
|
g_pCoTaskMemFree(pProps);
|
|
hr = IHNetConnection_GetGuid(pConn, &pGuid);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
RasGuidToSharedConnection(pGuid, Connection);
|
|
g_pCoTaskMemFree(pGuid);
|
|
}
|
|
}
|
|
else if (SUCCEEDED(hr))
|
|
{
|
|
LPWSTR pszwName;
|
|
LPWSTR pszwPath;
|
|
|
|
g_pCoTaskMemFree(pProps);
|
|
|
|
hr = IHNetConnection_GetName(pConn, &pszwName);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = IHNetConnection_GetRasPhonebookPath(pConn, &pszwPath);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
RasEntryToSharedConnection(pszwPath, pszwName, Connection);
|
|
|
|
g_pCoTaskMemFree(pszwPath);
|
|
}
|
|
|
|
g_pCoTaskMemFree(pszwName);
|
|
}
|
|
}
|
|
|
|
IHNetConnection_Release(pConn);
|
|
}
|
|
|
|
if (fUninitializeCOM)
|
|
{
|
|
g_pCoUninitialize();
|
|
}
|
|
|
|
return SUCCEEDED(hr) ? NO_ERROR : ERROR_CAN_NOT_COMPLETE;
|
|
|
|
} // CsQuerySharedConnection
|
|
|
|
#if 0
|
|
|
|
|
|
ULONG
|
|
CsQuerySharedPrivateLan(
|
|
GUID* LanGuid
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to retrieve the private LAN connection, if any.
|
|
|
|
Arguments:
|
|
|
|
LanGuid - receives the retrieved GUID.
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
HANDLE Key;
|
|
PKEY_VALUE_PARTIAL_INFORMATION Information;
|
|
NTSTATUS status;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
//
|
|
// Open the 'SharedAccess\Parameters' key, read the 'SharedPrivateLan'
|
|
// value, and convert it to a GUID
|
|
//
|
|
|
|
status = CsOpenKey(&Key, KEY_READ, c_szSharedAccessParametersKey);
|
|
if (!NT_SUCCESS(status)) {
|
|
TRACE1("CsQuerySharedPrivateLan: NtOpenKey=%x", status);
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
status = CsQueryValueKey(Key, c_szSharedPrivateLan, &Information);
|
|
NtClose(Key);
|
|
if (!NT_SUCCESS(status)) { return NO_ERROR; }
|
|
|
|
RtlInitUnicodeString(&UnicodeString, (PWCHAR)Information->Data);
|
|
status = RtlGUIDFromString(&UnicodeString, LanGuid);
|
|
Free(Information);
|
|
return NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
|
|
|
|
} // CsQuerySharedPrivateLan
|
|
|
|
|
|
ULONG
|
|
CsQuerySharedPrivateLanAddress(
|
|
PULONG Address
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to retrieve the IP address assigned
|
|
to the shared private LAN interface.
|
|
|
|
Arguments:
|
|
|
|
Address - on output, receives the IP address of the shared private LAN
|
|
interface.
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG AdapterIndex;
|
|
PALLOCATEANDGETIPADDRTABLEFROMSTACK AllocateAndGetIpAddrTableFromStack;
|
|
ULONG Error;
|
|
PGETINTERFACEINFO GetInterfaceInfo;
|
|
HINSTANCE Hinstance;
|
|
ULONG i;
|
|
PKEY_VALUE_PARTIAL_INFORMATION Information;
|
|
HANDLE Key = NULL;
|
|
NTSTATUS status;
|
|
PMIB_IPADDRTABLE Table;
|
|
|
|
if (!Address) { return ERROR_INVALID_PARAMETER; }
|
|
|
|
//
|
|
// Open the service's Parameters key and attempt to retrieve
|
|
// the GUID for the shared private LAN interface.
|
|
//
|
|
|
|
status = CsOpenKey(&Key, KEY_READ, c_szSharedAccessParametersKey);
|
|
if (!NT_SUCCESS(status)) {
|
|
TRACE1("CsQuerySharedPrivateLanAddress: NtOpenKey=%x", status);
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
status = CsQueryValueKey(Key, c_szSharedPrivateLan, &Information);
|
|
NtClose(Key);
|
|
if (!NT_SUCCESS(status)) { return ERROR_SHARING_NO_PRIVATE_LAN; }
|
|
|
|
//
|
|
// Load IPHLPAPI, which contains the 'GetInterfaceInfo' entrypoint
|
|
// that we will use to map this GUID to an adapter-index,
|
|
// as well as the 'AllocateAndGetIpAddrTableFromStack' entrypoint
|
|
// that we will use to map the adapter-index to an IP address list.
|
|
//
|
|
|
|
if (!(Hinstance = LoadLibraryW(c_szIphlpapiDll)) ||
|
|
!(AllocateAndGetIpAddrTableFromStack =
|
|
(PALLOCATEANDGETIPADDRTABLEFROMSTACK)
|
|
GetProcAddress(
|
|
Hinstance, c_szAllocateAndGetIpAddrTableFromStack
|
|
)) ||
|
|
!(GetInterfaceInfo =
|
|
(PGETINTERFACEINFO)
|
|
GetProcAddress(
|
|
Hinstance, c_szGetInterfaceInfo
|
|
))) {
|
|
if (Hinstance) { FreeLibrary(Hinstance); }
|
|
Free(Information);
|
|
return ERROR_PROC_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Map the GUID to an adapter index.
|
|
//
|
|
|
|
AdapterIndex =
|
|
CsMapGuidToAdapterIndex((PWCHAR)Information->Data, GetInterfaceInfo);
|
|
Free(Information);
|
|
if (AdapterIndex == (ULONG)-1) {
|
|
FreeLibrary(Hinstance);
|
|
return ERROR_SHARING_NO_PRIVATE_LAN;
|
|
}
|
|
|
|
//
|
|
// Map the adapter index to an IP address
|
|
//
|
|
|
|
Error =
|
|
AllocateAndGetIpAddrTableFromStack(
|
|
&Table,
|
|
FALSE,
|
|
GetProcessHeap(),
|
|
0
|
|
);
|
|
FreeLibrary(Hinstance);
|
|
if (Error) { return Error; }
|
|
for (i = 0; i < Table->dwNumEntries; i++) {
|
|
if (AdapterIndex == Table->table[i].dwIndex) {
|
|
break;
|
|
}
|
|
}
|
|
if (i >= Table->dwNumEntries) {
|
|
Error = ERROR_SHARING_NO_PRIVATE_LAN;
|
|
} else {
|
|
*Address = Table->table[i].dwAddr;
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, Table);
|
|
return Error;
|
|
|
|
} // CsQuerySharedPrivateLanAddress
|
|
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
CsQueryValueKey(
|
|
HANDLE Key,
|
|
const WCHAR ValueName[],
|
|
PKEY_VALUE_PARTIAL_INFORMATION* Information
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to obtain the value of a registry key.
|
|
|
|
Arguments:
|
|
|
|
Key - the key to be queried
|
|
|
|
ValueName - the value to be queried
|
|
|
|
Information - receives a pointer to the information read
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - NT status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
|
|
ULONG InformationLength;
|
|
NTSTATUS status;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
RtlInitUnicodeString(&UnicodeString, ValueName);
|
|
|
|
*Information = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
|
|
InformationLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
|
|
|
|
//
|
|
// Read the value's size
|
|
//
|
|
|
|
status =
|
|
NtQueryValueKey(
|
|
Key,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
*Information,
|
|
InformationLength,
|
|
&InformationLength
|
|
);
|
|
|
|
if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW &&
|
|
status != STATUS_BUFFER_TOO_SMALL) {
|
|
*Information = NULL;
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Allocate space for the value's size
|
|
//
|
|
|
|
*Information = (PKEY_VALUE_PARTIAL_INFORMATION)Malloc(InformationLength+2);
|
|
if (!*Information) { return STATUS_NO_MEMORY; }
|
|
|
|
//
|
|
// Read the value's data
|
|
//
|
|
|
|
status =
|
|
NtQueryValueKey(
|
|
Key,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
*Information,
|
|
InformationLength,
|
|
&InformationLength
|
|
);
|
|
if (!NT_SUCCESS(status)) { Free(*Information); *Information = NULL; }
|
|
return status;
|
|
|
|
} // CsQueryValueKey
|
|
|
|
#if 0
|
|
|
|
|
|
ULONG
|
|
CsRenameSharedConnection(
|
|
LPRASSHARECONN NewConnection
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to change the name of the currently-shared
|
|
connection, if any. It is assumed that the private LAN will remain
|
|
unchanged, and that the connection which is currently shared is a dialup
|
|
connection.
|
|
|
|
Arguments:
|
|
|
|
NewConnection - the new name for the shared connection
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE AdminHandle;
|
|
PUCHAR Buffer;
|
|
LPRASSHARECONN OldConnection;
|
|
ULONG Error;
|
|
PUCHAR Header;
|
|
HANDLE Key;
|
|
PKEY_VALUE_PARTIAL_INFORMATION Information;
|
|
HANDLE InterfaceHandle;
|
|
ULONG Length;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE ServerHandle;
|
|
NTSTATUS status;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
//
|
|
// Open the 'SharedAccess\Parameters' key,
|
|
// and read the 'SharedConnection' value
|
|
//
|
|
|
|
status = CsOpenKey(&Key, KEY_READ, c_szSharedAccessParametersKey);
|
|
if (!NT_SUCCESS(status)) {
|
|
TRACE1("CsRenameSharedConnection: NtOpenKey=%x", status);
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
status = CsQueryValueKey(Key, c_szSharedConnection, &Information);
|
|
NtClose(Key);
|
|
if (!NT_SUCCESS(status)) { return NO_ERROR; }
|
|
|
|
//
|
|
// Validate the data retrieved
|
|
//
|
|
|
|
if (Information->DataLength != sizeof(RASSHARECONN) ||
|
|
((LPRASSHARECONN)Information->Data)->dwSize != sizeof(RASSHARECONN)
|
|
) {
|
|
TRACE2(
|
|
"CsRenameSharedConnection: invalid length %d (size=%d) in registry",
|
|
Information->DataLength, ((LPRASSHARECONN)Information->Data)->dwSize
|
|
);
|
|
Free(Information); return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Ensure that the connection which was shared is not a LAN connection,
|
|
// and if so proceed to share the new connection instead.
|
|
//
|
|
|
|
OldConnection = (LPRASSHARECONN)Information->Data;
|
|
if (OldConnection->fIsLanConnection) {
|
|
TRACE("CsRenameSharedConnection: cannot rename shared LAN connection");
|
|
Free(Information); return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Clear any cached credentials for the old connection,
|
|
// and share the new connection.
|
|
//
|
|
|
|
RasSetSharedConnectionCredentials(OldConnection, NULL);
|
|
Free(Information);
|
|
|
|
return CsShareConnection(NewConnection);
|
|
|
|
} // CsRenameSharedConnection
|
|
|
|
|
|
ULONG
|
|
CsSetupSharedPrivateLan(
|
|
REFGUID LanGuid,
|
|
BOOLEAN EnableSharing
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to configure the designated private connection.
|
|
|
|
Arguments:
|
|
|
|
LanGuid - identifies the LAN connection to be configured
|
|
|
|
EnableSharing - if TRUE, sharing is enabled and the static address is set;
|
|
otherwise, sharing is disabled.
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
CS_ADDRESS_INFORMATION AddressInformation;
|
|
PALLOCATEANDGETIPADDRTABLEFROMSTACK AllocateAndGetIpAddrTableFromStack;
|
|
ANSI_STRING AnsiString;
|
|
ULONG Error;
|
|
PGETINTERFACEINFO GetInterfaceInfo;
|
|
HINSTANCE Hinstance;
|
|
ULONG i;
|
|
HANDLE Key = NULL;
|
|
UNICODE_STRING LanGuidString;
|
|
ULONG ScopeAddress;
|
|
ULONG ScopeMask;
|
|
PSETADAPTERIPADDRESS SetAdapterIpAddress;
|
|
ULONG Size;
|
|
NTSTATUS status;
|
|
PMIB_IPADDRTABLE Table;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
//
|
|
// To install or remove the static private IP address,
|
|
// we make use of several entrypoints in IPHLPAPI.DLL,
|
|
// which we now load dynamically.
|
|
//
|
|
|
|
RtlStringFromGUID(LanGuid, &UnicodeString);
|
|
RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
|
|
if (!(Hinstance = LoadLibraryW(c_szIphlpapiDll)) ||
|
|
!(AllocateAndGetIpAddrTableFromStack =
|
|
(PALLOCATEANDGETIPADDRTABLEFROMSTACK)
|
|
GetProcAddress(
|
|
Hinstance, c_szAllocateAndGetIpAddrTableFromStack
|
|
)) ||
|
|
!(GetInterfaceInfo =
|
|
(PGETINTERFACEINFO)
|
|
GetProcAddress(
|
|
Hinstance, c_szGetInterfaceInfo
|
|
)) ||
|
|
!(SetAdapterIpAddress =
|
|
(PSETADAPTERIPADDRESS)
|
|
GetProcAddress(
|
|
Hinstance, c_szSetAdapterIpAddress
|
|
))) {
|
|
if (Hinstance) { FreeLibrary(Hinstance); }
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
RtlFreeAnsiString(&AnsiString);
|
|
return ERROR_PROC_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Determine whether some LAN adapter other than the private LAN
|
|
// is already using a 169.254.0.0 address.
|
|
// In the process, make sure that the private LAN has only one
|
|
// IP address (otherwise, 'SetAdapterIpAddress' fails.)
|
|
//
|
|
|
|
CsQueryScopeInformation(&Key, &ScopeAddress, &ScopeMask);
|
|
if (!Key) {
|
|
FreeLibrary(Hinstance);
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
RtlFreeAnsiString(&AnsiString);
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
Error =
|
|
AllocateAndGetIpAddrTableFromStack(
|
|
&Table,
|
|
FALSE,
|
|
GetProcessHeap(),
|
|
0
|
|
);
|
|
if (!Error) {
|
|
ULONG Index;
|
|
ULONG Count;
|
|
Index = CsMapGuidToAdapterIndex(UnicodeString.Buffer, GetInterfaceInfo);
|
|
for (i = 0, Count = 0; i < Table->dwNumEntries; i++) {
|
|
if (Index == Table->table[i].dwIndex) {
|
|
++Count;
|
|
} else if ((Table->table[i].dwAddr & ScopeMask) ==
|
|
(ScopeAddress & ScopeMask)) {
|
|
//
|
|
// It appears that some other LAN adapter has an address in
|
|
// the proposed scope.
|
|
// This may happen when multiple netcards go into autonet mode
|
|
// or when the RAS server is handing out autonet addresses.
|
|
// Therefore, as long as we're using the autonet scope,
|
|
// allow this behavior; otherwise prohibit it.
|
|
//
|
|
if ((ScopeAddress & ScopeMask) != 0x0000fea9) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (i < Table->dwNumEntries) {
|
|
Error = ERROR_SHARING_ADDRESS_EXISTS;
|
|
} else if (Count > 1) {
|
|
Error = ERROR_SHARING_MULTIPLE_ADDRESSES;
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, Table);
|
|
}
|
|
|
|
if (Error) {
|
|
FreeLibrary(Hinstance);
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
RtlFreeAnsiString(&AnsiString);
|
|
NtClose(Key);
|
|
return Error;
|
|
}
|
|
|
|
//
|
|
// Set the predefined static IP address for the private LAN,
|
|
// which we now read either from the registry or from the internal default.
|
|
//
|
|
// Before actually making the change, we capture the original IP address
|
|
// so that it can be restored when the user turns off shared access.
|
|
// Once the IP address is changed, we backup the original IP address
|
|
// in the shared access parameters key.
|
|
//
|
|
|
|
status =
|
|
CspCaptureAddressInformation(
|
|
UnicodeString.Buffer, &AddressInformation
|
|
);
|
|
|
|
Error =
|
|
SetAdapterIpAddress(
|
|
AnsiString.Buffer,
|
|
FALSE,
|
|
ScopeAddress,
|
|
ScopeMask,
|
|
0
|
|
);
|
|
if (!Error) {
|
|
if (NT_SUCCESS(status)) {
|
|
CspBackupAddressInformation(Key, &AddressInformation);
|
|
}
|
|
} else {
|
|
TRACE1("CsSetupSharedPrivateLan: SetAdapterIpAddress=%d", Error);
|
|
if (Error == ERROR_TOO_MANY_NAMES) {
|
|
Error = ERROR_SHARING_MULTIPLE_ADDRESSES;
|
|
} else {
|
|
//
|
|
// Query the state of the connection.
|
|
// If it is disconnected, convert the error code
|
|
// to something more informative.
|
|
//
|
|
UNICODE_STRING DeviceString;
|
|
NIC_STATISTICS NdisStatistics;
|
|
RtlInitUnicodeString(&DeviceString, c_szDevice);
|
|
RtlAppendUnicodeStringToString(&DeviceString, &UnicodeString);
|
|
NdisStatistics.Size = sizeof(NdisStatistics);
|
|
NdisQueryStatistics(&DeviceString, &NdisStatistics);
|
|
RtlFreeUnicodeString(&DeviceString);
|
|
if (NdisStatistics.MediaState == MEDIA_STATE_UNKNOWN) {
|
|
Error = ERROR_SHARING_HOST_ADDRESS_CONFLICT;
|
|
} else if (NdisStatistics.DeviceState != DEVICE_STATE_CONNECTED ||
|
|
NdisStatistics.MediaState != MEDIA_STATE_CONNECTED) {
|
|
Error = ERROR_SHARING_NO_PRIVATE_LAN;
|
|
}
|
|
}
|
|
}
|
|
|
|
CspCleanupAddressInformation(&AddressInformation);
|
|
FreeLibrary(Hinstance);
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
RtlFreeAnsiString(&AnsiString);
|
|
if (Error) { NtClose(Key); return Error; }
|
|
|
|
//
|
|
// All went well above; now we save the name of the private LAN connection
|
|
// under the 'SharedAccess\\Parameters' registry key.
|
|
//
|
|
|
|
RtlStringFromGUID(LanGuid, &LanGuidString);
|
|
RtlInitUnicodeString(&UnicodeString, c_szSharedPrivateLan);
|
|
status =
|
|
NtSetValueKey(
|
|
Key,
|
|
&UnicodeString,
|
|
0,
|
|
REG_SZ,
|
|
LanGuidString.Buffer,
|
|
LanGuidString.Length + sizeof(WCHAR)
|
|
);
|
|
NtClose(Key);
|
|
RtlFreeUnicodeString(&LanGuidString);
|
|
if (!NT_SUCCESS(status)) { return RtlNtStatusToDosError(status); }
|
|
return NO_ERROR;
|
|
|
|
} // CsSetupSharedPrivateLan
|
|
|
|
|
|
ULONG
|
|
CsSetSharedPrivateLan(
|
|
REFGUID LanGuid
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to (re)configure the designated private connection
|
|
|
|
Arguments:
|
|
|
|
LanGuid - identifies the new LAN connection to be configured
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE Key;
|
|
ULONG Error;
|
|
NTSTATUS status;
|
|
PKEY_VALUE_PARTIAL_INFORMATION Information;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
|
|
if (!NT_SUCCESS(status)) {
|
|
TRACE1("CsSetSharedPrivateLan: CsOpenKey=%x", status);
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
//
|
|
// Remove old information (and reset old interface) in registry if present
|
|
//
|
|
|
|
status = CsQueryValueKey(Key, c_szSharedPrivateLan, &Information);
|
|
RtlInitUnicodeString(&UnicodeString, c_szSharedPrivateLan);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
if (NT_SUCCESS(status)) {
|
|
CspRestoreAddressInformation(Key, (PWCHAR)Information->Data);
|
|
Free(Information);
|
|
}
|
|
|
|
//
|
|
// Setup the private network with a private address
|
|
//
|
|
|
|
Error = CsSetupSharedPrivateLan(LanGuid, TRUE);
|
|
if (Error) {
|
|
TRACE1("CsSetSharedPrivateLan: CsSetupSharedPrivateLan=%d",Error);
|
|
return Error;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // CsSetSharedPrivateLan
|
|
|
|
|
|
ULONG
|
|
CsShareConnection(
|
|
LPRASSHARECONN Connection
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine enables sharing on the connection with the given name.
|
|
|
|
Arguments:
|
|
|
|
Connection - the connection to be shared
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING BindList;
|
|
HANDLE Key;
|
|
UNICODE_STRING LowerComponent;
|
|
IP_PNP_RECONFIG_REQUEST Request;
|
|
NTSTATUS status;
|
|
UNICODE_STRING UpperComponent;
|
|
ULONG Value;
|
|
UNICODE_STRING ValueString;
|
|
|
|
//
|
|
// Set the 'SharedConnection' value in the registry,
|
|
// under the 'SharedAccess\Parameters' key.
|
|
//
|
|
|
|
status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
|
|
if (!NT_SUCCESS(status)) {
|
|
TRACE1("CsShareConnection: CsOpenKey=%x", status);
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
RtlInitUnicodeString(&ValueString, c_szSharedConnection);
|
|
status =
|
|
NtSetValueKey(
|
|
Key,
|
|
&ValueString,
|
|
0,
|
|
REG_BINARY,
|
|
Connection,
|
|
Connection->dwSize
|
|
);
|
|
|
|
NtClose(Key);
|
|
if (!NT_SUCCESS(status)) {
|
|
TRACE1("CsShareConnection: NtSetValueKey=%x", status);
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // CsShareConnection
|
|
|
|
#endif
|
|
|
|
|
|
VOID
|
|
CsShutdownModule(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to clean up state for the module.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
Environment:
|
|
|
|
Invoked with 'CsCriticalSection' held by the caller.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (CsInitialized) {
|
|
if (CsOle32Dll) { FreeLibrary(CsOle32Dll); CsOle32Dll = NULL; }
|
|
}
|
|
} // CsShutdownModule
|
|
|
|
#if 0
|
|
|
|
|
|
ULONG
|
|
CsStartService(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to start the routing and remote access service.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
Revision History:
|
|
|
|
Loosely based on CService::HrMoveOutOfState by KennT.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
SC_HANDLE ScmHandle;
|
|
SC_HANDLE ServiceHandle;
|
|
SERVICE_STATUS ServiceStatus;
|
|
ULONG Timeout;
|
|
|
|
//
|
|
// Connect to the service control manager
|
|
//
|
|
|
|
ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (!ScmHandle) { return GetLastError(); }
|
|
|
|
do {
|
|
|
|
//
|
|
// Open the shared access service
|
|
//
|
|
|
|
ServiceHandle =
|
|
OpenService(ScmHandle, c_szSharedAccess, SERVICE_ALL_ACCESS);
|
|
if (!ServiceHandle) { Error = GetLastError(); break; }
|
|
|
|
//
|
|
// Mark it as auto-start
|
|
//
|
|
|
|
ChangeServiceConfig(
|
|
ServiceHandle,
|
|
SERVICE_NO_CHANGE,
|
|
SERVICE_AUTO_START,
|
|
SERVICE_NO_CHANGE,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Attempt to start the service
|
|
//
|
|
|
|
if (!StartService(ServiceHandle, 0, NULL)) {
|
|
Error = GetLastError();
|
|
if (Error == ERROR_SERVICE_ALREADY_RUNNING) { Error = NO_ERROR; }
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Wait for the service to start
|
|
//
|
|
|
|
Timeout = 30;
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
|
|
do {
|
|
|
|
//
|
|
// Query the service's state
|
|
//
|
|
|
|
if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
|
|
Error = GetLastError(); break;
|
|
}
|
|
|
|
//
|
|
// See if the service has started
|
|
//
|
|
|
|
if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
|
|
Error = NO_ERROR; break;
|
|
} else if (ServiceStatus.dwCurrentState == SERVICE_STOPPED ||
|
|
ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Wait a little longer
|
|
//
|
|
|
|
Sleep(1000);
|
|
|
|
} while(Timeout--);
|
|
|
|
} while(FALSE);
|
|
|
|
if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
|
|
CloseServiceHandle(ScmHandle);
|
|
|
|
return Error;
|
|
|
|
} // CsStartService
|
|
|
|
|
|
VOID
|
|
CsStopService(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to uninstall the service.
|
|
The routine, however, does not uninstall the service at all,
|
|
which just goes to show you...
|
|
Instead, it marks the service as demand-start.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
SC_HANDLE ScmHandle;
|
|
SC_HANDLE ServiceHandle;
|
|
SERVICE_STATUS ServiceStatus;
|
|
|
|
//
|
|
// Connect to the service control manager
|
|
//
|
|
|
|
ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (!ScmHandle) { return; }
|
|
|
|
do {
|
|
|
|
//
|
|
// Open the shared access service
|
|
//
|
|
|
|
ServiceHandle =
|
|
OpenService(ScmHandle, c_szSharedAccess, SERVICE_ALL_ACCESS);
|
|
if (!ServiceHandle) { Error = GetLastError(); break; }
|
|
|
|
//
|
|
// Mark it as demand-start
|
|
//
|
|
|
|
ChangeServiceConfig(
|
|
ServiceHandle,
|
|
SERVICE_NO_CHANGE,
|
|
SERVICE_DEMAND_START,
|
|
SERVICE_NO_CHANGE,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Attempt to stop the service
|
|
//
|
|
|
|
ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
|
|
|
|
} while(FALSE);
|
|
|
|
if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
|
|
CloseServiceHandle(ScmHandle);
|
|
|
|
return;
|
|
|
|
|
|
} // CsStopService
|
|
|
|
|
|
ULONG
|
|
CsUnshareConnection(
|
|
BOOLEAN RemovePrivateLan,
|
|
PBOOLEAN Shared
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to unshare a shared connection.
|
|
This is accomplished by removing the settings from the registry.
|
|
|
|
Arguments:
|
|
|
|
RemovePrivateLan - if TRUE, the private LAN connection is reset
|
|
to use DHCP rather than the NAT private address.
|
|
|
|
Shared - receives 'TRUE' if a shared connection was found, FALSE otherwise.
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPRASSHARECONN Connection;
|
|
HANDLE Key;
|
|
PKEY_VALUE_PARTIAL_INFORMATION Information;
|
|
PIP_NAT_INTERFACE_INFO Info;
|
|
GUID LanGuid;
|
|
ULONG Length;
|
|
ULONG Size;
|
|
NTSTATUS status;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
if (Shared) { *Shared = FALSE; }
|
|
|
|
//
|
|
// Open the 'SharedAccess\Parameters' key, read the 'SharedConnection'
|
|
// value, and validate the information retrieved.
|
|
//
|
|
|
|
status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
|
|
if (!NT_SUCCESS(status)) {
|
|
TRACE1("CsUnshareConnection: NtOpenKey=%x", status);
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
//
|
|
// Read the 'SharedConnection' value
|
|
//
|
|
|
|
status = CsQueryValueKey(Key, c_szSharedConnection, &Information);
|
|
if (!NT_SUCCESS(status)) { return NO_ERROR; }
|
|
|
|
if (Information->DataLength != sizeof(RASSHARECONN) ||
|
|
((LPRASSHARECONN)Information->Data)->dwSize != sizeof(RASSHARECONN)) {
|
|
TRACE2(
|
|
"CsUnshareConnection: invalid length %d (size=%d) in registry",
|
|
Information->DataLength, ((LPRASSHARECONN)Information->Data)->dwSize
|
|
);
|
|
NtClose(Key); Free(Information); return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Inform the caller that a connection was indeed originally shared,
|
|
// clear any credentials cached for that connection, free the buffer
|
|
// containing the shared connection's information, and delete the
|
|
// 'SharedConnection' value from the registry.
|
|
//
|
|
|
|
if (Shared) { *Shared = TRUE; }
|
|
Connection = (LPRASSHARECONN)Information->Data;
|
|
RasSetSharedConnectionCredentials(Connection, NULL);
|
|
|
|
Free(Information);
|
|
RtlInitUnicodeString(&UnicodeString, c_szSharedConnection);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
|
|
//
|
|
// See if we're resetting the private LAN connection,
|
|
// and if so, read (and delete) the 'SharedPrivateLan' value.
|
|
// In the process, restore the original address-information
|
|
// for the connection.
|
|
//
|
|
|
|
if (RemovePrivateLan) {
|
|
status = CsQueryValueKey(Key, c_szSharedPrivateLan, &Information);
|
|
RtlInitUnicodeString(&UnicodeString, c_szSharedPrivateLan);
|
|
NtDeleteValueKey(Key, &UnicodeString);
|
|
if (NT_SUCCESS(status)) {
|
|
CspRestoreAddressInformation(Key, (PWCHAR)Information->Data);
|
|
Free(Information);
|
|
}
|
|
}
|
|
|
|
NtClose(Key);
|
|
return NO_ERROR;
|
|
|
|
} // CsUnshareConnection
|
|
|
|
|
|
WCHAR*
|
|
StrDupW(
|
|
LPCWSTR psz
|
|
)
|
|
{
|
|
WCHAR* psz2 = Malloc((lstrlenW(psz) + 1) * sizeof(WCHAR));
|
|
if (psz2) { lstrcpyW(psz2, psz); }
|
|
return psz2;
|
|
}
|
|
|
|
|
|
VOID
|
|
TestBackupAddress(
|
|
PWCHAR Guid
|
|
)
|
|
{
|
|
HANDLE Key;
|
|
CS_ADDRESS_INFORMATION Information;
|
|
NTSTATUS status;
|
|
status = CspCaptureAddressInformation(Guid, &Information);
|
|
if (NT_SUCCESS(status)) {
|
|
status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
|
|
if (NT_SUCCESS(status)) {
|
|
CspBackupAddressInformation(Key, &Information);
|
|
NtClose(Key);
|
|
}
|
|
CspCleanupAddressInformation(&Information);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
TestRestoreAddress(
|
|
PWCHAR Guid
|
|
)
|
|
{
|
|
HANDLE Key;
|
|
NTSTATUS status;
|
|
status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
|
|
if (NT_SUCCESS(status)) {
|
|
status = CspRestoreAddressInformation(Key, Guid);
|
|
}
|
|
}
|
|
|
|
VOID CsRefreshNetConnections(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL bUninitializeCOM = TRUE;
|
|
HRESULT hResult;
|
|
|
|
ASSERT(NULL != g_pCoInitializeEx);
|
|
ASSERT(NULL != g_pCoCreateInstance);
|
|
ASSERT(NULL != g_pCoUninitialize);
|
|
|
|
hResult = g_pCoInitializeEx(NULL, COINIT_MULTITHREADED|COINIT_DISABLE_OLE1DDE); // we don't know if the thread is COM or not
|
|
if(RPC_E_CHANGED_MODE == hResult)
|
|
{
|
|
hResult = S_OK;
|
|
bUninitializeCOM = FALSE;
|
|
}
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
INetConnectionRefresh * pRefresh = NULL;
|
|
hResult = g_pCoCreateInstance(&CLSID_ConnectionManager, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD, &IID_INetConnectionRefresh, (void**) &pRefresh);
|
|
if(SUCCEEDED(hResult))
|
|
{
|
|
|
|
g_pCoSetProxyBlanket((IUnknown*) pRefresh, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
|
|
// ignore error as the interface is not invalidated by error
|
|
|
|
hResult = INetConnectionRefresh_RefreshAll(pRefresh);
|
|
INetConnectionRefresh_Release(pRefresh);
|
|
}
|
|
|
|
if(TRUE == bUninitializeCOM)
|
|
{
|
|
g_pCoUninitialize();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|