windows-nt/Source/XPSP1/NT/net/config/shell/folder/trytofix.cpp
2020-09-26 16:20:57 +08:00

506 lines
13 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2001.
//
// File: T R Y T O F I X . C P P
//
// Contents: Code for the "repair" command
//
// Notes:
//
// Author: nsun Jan 2001
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "wzcsapi.h"
#include "nsbase.h"
#include "ncstring.h"
#include "nsres.h"
#include "ncperms.h"
#include "ncnetcon.h"
#include "repair.h"
extern "C"
{
#include <dhcpcapi.h>
extern DWORD DhcpStaticRefreshParams(IN LPWSTR Adapter);
extern DWORD DhcpAcquireParametersByBroadcast(IN LPWSTR AdapterName);
}
#include <dnsapi.h>
#include "nbtioctl.h"
HRESULT HrGetAdapterSettings(LPCWSTR pszGuid, BOOL * pfDhcp, DWORD * pdwIndex);
HRESULT PurgeNbt(HANDLE NbtHandle);
HRESULT ReleaseRefreshNetBt(HANDLE NbtHandle);
//+---------------------------------------------------------------------------
//
// Function: HrTryToFix
//
// Purpose: Do the fix
//
// Arguments:
// guidConnection [in] guid of the connection to fix
// strMessage [out] the message containing the results
//
// Returns:
// S_OK succeeded
// S_FALSE some fix operation failed
//
HRESULT HrTryToFix(GUID & guidConnection, tstring & strMessage)
{
HRESULT hr = S_OK;
DWORD dwRet = ERROR_SUCCESS;
BOOL fRet = TRUE;
WCHAR wszGuid[c_cchGuidWithTerm] = {0};
tstring strFailures = L"";
strMessage = L"";
::StringFromGUID2(guidConnection,
wszGuid,
c_cchGuidWithTerm);
BOOL fDhcp = FALSE;
DWORD dwIfIndex = 0;
//re-autheticate for 802.1X. This is a asynchronous call and there is
//no meaningful return value. So ignore the return value
WZCEapolReAuthenticate(NULL, wszGuid);
//only do the fix when TCP/IP is enabled for this connection
//also get the interface index that is needed when flushing Arp table
hr = HrGetAdapterSettings(wszGuid, &fDhcp, &dwIfIndex);
if (FAILED(hr))
{
strMessage = SzLoadIds((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) ?
IDS_FIX_NO_TCP : IDS_FIX_TCP_FAIL);
return S_FALSE;
}
//renew the lease if DHCP is enabled
if (fDhcp)
{
dwRet = DhcpAcquireParametersByBroadcast(wszGuid);
if (ERROR_SUCCESS != dwRet)
{
TraceError("DhcpAcquireParametersByBroadcast", HRESULT_FROM_WIN32(dwRet));
strFailures += SzLoadIds(IDS_FIX_ERR_RENEW_DHCP);
hr = S_FALSE;
}
}
//purge the ARP table if the user is admin or Netcfg Ops
//Other user are not allowed to do this
if (FIsUserAdmin() || FIsUserNetworkConfigOps())
{
dwRet = FlushIpNetTable(dwIfIndex);
if (NO_ERROR != dwRet)
{
TraceError("FlushIpNetTable", HRESULT_FROM_WIN32(dwRet));
strFailures += SzLoadIds(IDS_FIX_ERR_FLUSH_ARP);
hr = S_FALSE;
}
}
//puge the NetBT table and Renew name registration
HANDLE NbtHandle = INVALID_HANDLE_VALUE;
if (SUCCEEDED(OpenNbt(wszGuid, &NbtHandle)))
{
if (FAILED(PurgeNbt(NbtHandle)))
{
strFailures += SzLoadIds(IDS_FIX_ERR_PURGE_NBT);
hr = S_FALSE;
}
if (FAILED(ReleaseRefreshNetBt(NbtHandle)))
{
strFailures += SzLoadIds(IDS_FIX_ERR_RR_NBT);
hr = S_FALSE;
}
NtClose(NbtHandle);
NbtHandle = INVALID_HANDLE_VALUE;
}
else
{
strFailures += SzLoadIds(IDS_FIX_ERR_PURGE_NBT);
strFailures += SzLoadIds(IDS_FIX_ERR_RR_NBT);
hr = S_FALSE;
}
//flush DNS cache
fRet = DnsFlushResolverCache();
if (!fRet)
{
strFailures += SzLoadIds(IDS_FIX_ERR_FLUSH_DNS);
hr = S_FALSE;
}
//re-register DNS name
dwRet = DhcpStaticRefreshParams(NULL);
if (ERROR_SUCCESS != dwRet)
{
strFailures += SzLoadIds(IDS_FIX_ERR_REG_DNS);
hr = S_FALSE;
}
if (S_OK == hr)
{
strMessage = SzLoadIds(IDS_FIX_SUCCEED);
}
else
{
PCWSTR pszFormat = SzLoadIds(IDS_FIX_ERROR_FORMAT);
PWSTR pszText = NULL;
LPCWSTR pcszFailures = strFailures.c_str();
FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszFormat, 0, 0, (PWSTR)&pszText, 0, (va_list *)&pcszFailures);
if (pszText)
{
strMessage = pszText;
LocalFree(pszText);
}
else
{
strMessage = SzLoadIds(IDS_FIX_ERROR);
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: OpenNbt
//
// Purpose: Open the NetBT driver
//
// Arguments:
// pwszGuid [in] guid of the adapter
// pHandle [out] contains the handle of the Netbt driver
//
// Returns:
//
HRESULT OpenNbt(
LPWSTR pwszGuid,
HANDLE * pHandle)
{
const WCHAR c_szNbtDevicePrefix[] = L"\\Device\\NetBT_Tcpip_";
HRESULT hr = S_OK;
tstring strDevice;
HANDLE StreamHandle = NULL;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING uc_name_string;
NTSTATUS status;
Assert(pHandle);
Assert(pwszGuid);
strDevice = c_szNbtDevicePrefix;
strDevice += pwszGuid;
RtlInitUnicodeString(&uc_name_string, strDevice.c_str());
InitializeObjectAttributes (&ObjectAttributes,
&uc_name_string,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL);
status = NtCreateFile (&StreamHandle,
SYNCHRONIZE | GENERIC_EXECUTE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
0,
NULL,
0);
if (NT_SUCCESS(status))
{
*pHandle = StreamHandle;
}
else
{
*pHandle = INVALID_HANDLE_VALUE;
hr = E_FAIL;
}
TraceError("OpenNbt", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: PurgeNbt
//
// Purpose: Purge the NetBt cache
//
// Arguments: NbtHandle [in] handle of the Netbt driver
//
// Returns:
//
HRESULT PurgeNbt(HANDLE NbtHandle)
{
HRESULT hr = S_OK;
CHAR Buffer = 0;
DWORD dwBytesOut = 0;
if (!DeviceIoControl(NbtHandle,
IOCTL_NETBT_PURGE_CACHE,
NULL,
0,
&Buffer,
1,
&dwBytesOut,
NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
TraceError("PurgeNbt", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: ReleaseRefreshNetBt
//
// Purpose: release and then refresh the name on the WINS server
//
// Arguments: NbtHandle [in] handle of the Netbt driver
//
// Returns:
//
HRESULT ReleaseRefreshNetBt(HANDLE NbtHandle)
{
HRESULT hr = S_OK;
CHAR Buffer = 0;
DWORD dwBytesOut = 0;
if (!DeviceIoControl(NbtHandle,
IOCTL_NETBT_NAME_RELEASE_REFRESH,
NULL,
0,
&Buffer,
1,
&dwBytesOut,
NULL))
{
DWORD dwErr = GetLastError();
//RELEASE_REFRESH can at most do every two minutes
//So if the user perform 2 RELEASE_REFRESH within 2 minutes, the 2nd
//one will fail with ERROR_SEM_TIMEOUT. We ignore this particular error
if (ERROR_SEM_TIMEOUT != dwErr)
{
hr = HRESULT_FROM_WIN32(dwErr);
}
}
TraceError("ReleaseRefreshNetBt", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrGetAdapterSettings
//
// Purpose: Query the stack to know whether dhcp is enabled
//
// Arguments: pszGuid [in] guid of the adapter
// pfDhcp [out] contains whether dhcp is enabled
// pdwIndex [out] contains the index of this adapter
//
// Returns:
//
HRESULT HrGetAdapterSettings(LPCWSTR pszGuid, BOOL * pfDhcp, DWORD * pdwIndex)
{
HRESULT hr = S_OK;
PIP_ADAPTER_INFO pAdapterInfo = NULL;
DWORD dwOutBufLen = 0;
DWORD dwRet = ERROR_SUCCESS;
Assert(pfDhcp);
Assert(pszGuid);
dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen);
if (dwRet == ERROR_BUFFER_OVERFLOW)
{
pAdapterInfo = (PIP_ADAPTER_INFO) CoTaskMemAlloc(dwOutBufLen);
if (NULL == pAdapterInfo)
return E_OUTOFMEMORY;
}
else if (ERROR_SUCCESS == dwRet)
{
return E_FAIL;
}
else
{
return HRESULT_FROM_WIN32(dwRet);
}
dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen);
if (ERROR_SUCCESS != dwRet)
{
CoTaskMemFree(pAdapterInfo);
return HRESULT_FROM_WIN32(dwRet);
}
BOOL fFound = FALSE;
PIP_ADAPTER_INFO pAdapterInfoEnum = pAdapterInfo;
while (pAdapterInfoEnum)
{
USES_CONVERSION;
if (lstrcmp(pszGuid, A2W(pAdapterInfoEnum->AdapterName)) == 0)
{
if (pdwIndex)
{
*pdwIndex = pAdapterInfoEnum->Index;
}
*pfDhcp = pAdapterInfoEnum->DhcpEnabled;
fFound = TRUE;
break;
}
pAdapterInfoEnum = pAdapterInfoEnum->Next;
}
CoTaskMemFree(pAdapterInfo);
if (!fFound)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
return hr;
}
HRESULT RepairConnectionInternal(
GUID & guidConnection,
LPWSTR * ppszMessage)
{
if (NULL != ppszMessage &&
IsBadWritePtr(ppszMessage, sizeof(LPWSTR)))
{
return E_INVALIDARG;
}
if (ppszMessage)
{
*ppszMessage = NULL;
}
if (!FHasPermission(NCPERM_Repair))
{
return E_ACCESSDENIED;
}
// Get the net connection manager
CComPtr<INetConnectionManager> spConnMan;
HRESULT hr = S_OK;
hr = CoCreateInstance(CLSID_ConnectionManager, NULL,
CLSCTX_ALL,
IID_INetConnectionManager,
(LPVOID *)&spConnMan);
if (FAILED(hr))
{
return hr;
}
Assert(spConnMan.p);
NcSetProxyBlanket(spConnMan);
CComPtr<IEnumNetConnection> spEnum;
hr = spConnMan->EnumConnections(NCME_DEFAULT, &spEnum);
spConnMan = NULL;
if (FAILED(hr))
{
return hr;
}
Assert(spEnum.p);
BOOL fFound = FALSE;
ULONG ulCount = 0;
INetConnection * pConn = NULL;
spEnum->Reset();
do
{
NETCON_PROPERTIES* pProps = NULL;
hr = spEnum->Next(1, &pConn, &ulCount);
if (SUCCEEDED(hr) && 1 == ulCount)
{
NcSetProxyBlanket(pConn);
hr = pConn->GetProperties(&pProps);
if (S_OK == hr)
{
if (IsEqualGUID(pProps->guidId, guidConnection))
{
fFound = TRUE;
//we only support LAN and Bridge adapters
if (NCM_LAN != pProps->MediaType && NCM_BRIDGE != pProps->MediaType)
{
hr = CO_E_NOT_SUPPORTED;
}
break;
}
FreeNetconProperties(pProps);
}
pConn->Release();
pConn = NULL;
}
}while (SUCCEEDED(hr) && 1 == ulCount);
if (!fFound)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
if (FAILED(hr))
{
return hr;
}
LPWSTR psz = NULL;
tstring strMessage;
hr = HrTryToFix(guidConnection, strMessage);
if (ppszMessage && S_OK != hr && strMessage.length())
{
psz = (LPWSTR) LocalAlloc(LPTR, (strMessage.length() + 1) * sizeof(WCHAR));
lstrcpy(psz, strMessage.c_str());
*ppszMessage = psz;
}
return hr;
}