Leaked source code of windows server 2003
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.

723 lines
20 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2001.
  5. //
  6. // File: T R Y T O F I X . C P P
  7. //
  8. // Contents: Code for the "repair" command
  9. //
  10. // Notes:
  11. //
  12. // Author: nsun Jan 2001
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "wzcsapi.h"
  18. #include "netshell.h"
  19. #include "nsbase.h"
  20. #include "ncstring.h"
  21. #include "nsres.h"
  22. #include "ncperms.h"
  23. #include "ncnetcon.h"
  24. #include "repair.h"
  25. extern "C"
  26. {
  27. #include <dhcpcapi.h>
  28. extern DWORD DhcpStaticRefreshParams(IN LPWSTR Adapter);
  29. extern DWORD DhcpAcquireParametersByBroadcast(IN LPWSTR AdapterName);
  30. }
  31. #include <dnsapi.h>
  32. #include "nbtioctl.h"
  33. #include <ntddip6.h>
  34. const WCHAR c_sz624svc[] = L"6to4";
  35. const DWORD SERVICE_CONTROL_6TO4_REGISER_DNS = 128;
  36. HRESULT HrGetAutoNetSetting(PWSTR pszGuid, DHCP_ADDRESS_TYPE * pAddrType);
  37. HRESULT HrGetAdapterSettings(LPCWSTR pszGuid, BOOL * pfDhcp, DWORD * pdwIndex);
  38. HRESULT PurgeNbt(HANDLE NbtHandle);
  39. HRESULT ReleaseRefreshNetBt(HANDLE NbtHandle);
  40. HRESULT HrRenewIPv6Interface(const GUID & guidConnection);
  41. HRESULT HrRegisterIPv6Dns();
  42. //+---------------------------------------------------------------------------
  43. //
  44. // Function: HrTryToFix
  45. //
  46. // Purpose: Do the fix
  47. //
  48. // Arguments:
  49. // guidConnection [in] guid of the connection to fix
  50. // strMessage [out] the message containing the results
  51. //
  52. // Returns:
  53. // S_OK succeeded
  54. // S_FALSE some fix operation failed
  55. //
  56. HRESULT HrTryToFix(GUID & guidConnection, tstring & strMessage)
  57. {
  58. HRESULT hr = S_OK;
  59. HRESULT hrTmp = S_OK;
  60. DWORD dwRet = ERROR_SUCCESS;
  61. BOOL fRet = TRUE;
  62. BOOL fUseAdditionErrorFormat = FALSE;
  63. WCHAR wszGuid[c_cchGuidWithTerm] = {0};
  64. tstring strFailures = L"";
  65. strMessage = L"";
  66. ::StringFromGUID2(guidConnection,
  67. wszGuid,
  68. c_cchGuidWithTerm);
  69. BOOL fDhcp = FALSE;
  70. DWORD dwIfIndex = 0;
  71. //re-autheticate for 802.1X. This is a asynchronous call and there is
  72. //no meaningful return value. So ignore the return value
  73. WZCEapolReAuthenticate(NULL, wszGuid);
  74. //since IPv6 calls are asnychronous and doesn't return back meaning failures
  75. //other than stuff like INVALID_PARAMETER, we ignore the errors
  76. HrRenewIPv6Interface(guidConnection);
  77. HrRegisterIPv6Dns();
  78. //only do the fix when TCP/IP is enabled for this connection
  79. //also get the interface index that is needed when flushing Arp table
  80. hrTmp = HrGetAdapterSettings(wszGuid, &fDhcp, &dwIfIndex);
  81. if (FAILED(hrTmp))
  82. {
  83. UINT uMsgId = 0;
  84. uMsgId = (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp) ?
  85. IDS_FIX_NO_TCP : IDS_FIX_TCP_FAIL;
  86. strMessage = SzLoadIds(uMsgId);
  87. return S_FALSE;
  88. }
  89. //renew the lease if DHCP is enabled
  90. if (fDhcp)
  91. {
  92. dwRet = DhcpAcquireParametersByBroadcast(wszGuid);
  93. if (ERROR_SUCCESS != dwRet)
  94. {
  95. TraceError("DhcpAcquireParametersByBroadcast", HRESULT_FROM_WIN32(dwRet));
  96. DHCP_ADDRESS_TYPE AddrType = UNKNOWN_ADDR;
  97. //Generate different messages based the DHCP address type.
  98. //if this is autonet or alternate address, that is not necessarily an error. Just produce an
  99. //informational message. In such a case we also need use the other kind of format to format other errors.
  100. //Otherwise, just treat it the same as other errors.
  101. if (SUCCEEDED(HrGetAutoNetSetting(wszGuid, &AddrType)))
  102. {
  103. switch (AddrType)
  104. {
  105. case AUTONET_ADDR:
  106. strMessage = SzLoadIds(IDS_FIX_ERR_RENEW_AUTONET);
  107. fUseAdditionErrorFormat = TRUE;
  108. break;
  109. case ALTERNATE_ADDR:
  110. strMessage = SzLoadIds(IDS_FIX_ERR_RENEW_ALTERNATE);
  111. fUseAdditionErrorFormat = TRUE;
  112. break;
  113. default:
  114. strFailures += SzLoadIds(IDS_FIX_ERR_RENEW_DHCP);
  115. break;
  116. }
  117. }
  118. else
  119. {
  120. strFailures += SzLoadIds(IDS_FIX_ERR_RENEW_DHCP);
  121. }
  122. hr = S_FALSE;
  123. }
  124. }
  125. //purge the ARP table if the user is admin or Netcfg Ops
  126. //Other user are not allowed to do this
  127. if (FIsUserAdmin() || FIsUserNetworkConfigOps())
  128. {
  129. dwRet = FlushIpNetTable(dwIfIndex);
  130. if (NO_ERROR != dwRet)
  131. {
  132. TraceError("FlushIpNetTable", HRESULT_FROM_WIN32(dwRet));
  133. strFailures += SzLoadIds(IDS_FIX_ERR_FLUSH_ARP);
  134. hr = S_FALSE;
  135. }
  136. }
  137. //puge the NetBT table and Renew name registration
  138. HANDLE NbtHandle = INVALID_HANDLE_VALUE;
  139. if (SUCCEEDED(OpenNbt(wszGuid, &NbtHandle)))
  140. {
  141. if (FAILED(PurgeNbt(NbtHandle)))
  142. {
  143. strFailures += SzLoadIds(IDS_FIX_ERR_PURGE_NBT);
  144. hr = S_FALSE;
  145. }
  146. if (FAILED(ReleaseRefreshNetBt(NbtHandle)))
  147. {
  148. strFailures += SzLoadIds(IDS_FIX_ERR_RR_NBT);
  149. hr = S_FALSE;
  150. }
  151. NtClose(NbtHandle);
  152. NbtHandle = INVALID_HANDLE_VALUE;
  153. }
  154. else
  155. {
  156. strFailures += SzLoadIds(IDS_FIX_ERR_PURGE_NBT);
  157. strFailures += SzLoadIds(IDS_FIX_ERR_RR_NBT);
  158. hr = S_FALSE;
  159. }
  160. //flush DNS cache
  161. fRet = DnsFlushResolverCache();
  162. if (!fRet)
  163. {
  164. strFailures += SzLoadIds(IDS_FIX_ERR_FLUSH_DNS);
  165. hr = S_FALSE;
  166. }
  167. //re-register DNS name
  168. dwRet = DhcpStaticRefreshParams(NULL);
  169. if (ERROR_SUCCESS != dwRet)
  170. {
  171. strFailures += SzLoadIds(IDS_FIX_ERR_REG_DNS);
  172. hr = S_FALSE;
  173. }
  174. if (S_OK == hr)
  175. {
  176. strMessage = SzLoadIds(IDS_FIX_SUCCEED);
  177. }
  178. else
  179. {
  180. //If the failure message is not empty, format the failure message.
  181. //If the failure message is empty, then most likely the DHCP renew
  182. //failure causes hr == S_FALSE. We already have a special error message
  183. //for it and no need of formating
  184. if (!strFailures.empty())
  185. {
  186. PCWSTR pszFormat = SzLoadIds(fUseAdditionErrorFormat ?
  187. IDS_FIX_ERROR_FORMAT_ADDITION : IDS_FIX_ERROR_FORMAT);
  188. PWSTR pszText = NULL;
  189. LPCWSTR pcszFailures = strFailures.c_str();
  190. FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  191. pszFormat, 0, 0, (PWSTR)&pszText, 0, (va_list *)&pcszFailures);
  192. if (pszText)
  193. {
  194. strMessage += pszText;
  195. LocalFree(pszText);
  196. }
  197. }
  198. if (strMessage.empty())
  199. {
  200. //there would be some error happens if we still haven't got any specific error message now.
  201. //Then we simply print a generic error message
  202. strMessage = SzLoadIds(IDS_FIX_ERROR);
  203. }
  204. }
  205. return hr;
  206. }
  207. //+---------------------------------------------------------------------------
  208. //
  209. // Function: OpenNbt
  210. //
  211. // Purpose: Open the NetBT driver
  212. //
  213. // Arguments:
  214. // pwszGuid [in] guid of the adapter
  215. // pHandle [out] contains the handle of the Netbt driver
  216. //
  217. // Returns:
  218. //
  219. HRESULT OpenNbt(
  220. LPWSTR pwszGuid,
  221. HANDLE * pHandle)
  222. {
  223. const WCHAR c_szNbtDevicePrefix[] = L"\\Device\\NetBT_Tcpip_";
  224. HRESULT hr = S_OK;
  225. tstring strDevice;
  226. HANDLE StreamHandle = NULL;
  227. OBJECT_ATTRIBUTES ObjectAttributes;
  228. IO_STATUS_BLOCK IoStatusBlock;
  229. UNICODE_STRING uc_name_string;
  230. NTSTATUS status;
  231. Assert(pHandle);
  232. Assert(pwszGuid);
  233. strDevice = c_szNbtDevicePrefix;
  234. strDevice += pwszGuid;
  235. RtlInitUnicodeString(&uc_name_string, strDevice.c_str());
  236. InitializeObjectAttributes (&ObjectAttributes,
  237. &uc_name_string,
  238. OBJ_CASE_INSENSITIVE,
  239. (HANDLE) NULL,
  240. (PSECURITY_DESCRIPTOR) NULL);
  241. status = NtCreateFile (&StreamHandle,
  242. SYNCHRONIZE | GENERIC_EXECUTE,
  243. &ObjectAttributes,
  244. &IoStatusBlock,
  245. NULL,
  246. FILE_ATTRIBUTE_NORMAL,
  247. FILE_SHARE_READ | FILE_SHARE_WRITE,
  248. FILE_OPEN_IF,
  249. 0,
  250. NULL,
  251. 0);
  252. if (NT_SUCCESS(status))
  253. {
  254. *pHandle = StreamHandle;
  255. }
  256. else
  257. {
  258. *pHandle = INVALID_HANDLE_VALUE;
  259. hr = E_FAIL;
  260. }
  261. TraceError("OpenNbt", hr);
  262. return hr;
  263. }
  264. //+---------------------------------------------------------------------------
  265. //
  266. // Function: PurgeNbt
  267. //
  268. // Purpose: Purge the NetBt cache
  269. //
  270. // Arguments: NbtHandle [in] handle of the Netbt driver
  271. //
  272. // Returns:
  273. //
  274. HRESULT PurgeNbt(HANDLE NbtHandle)
  275. {
  276. HRESULT hr = S_OK;
  277. CHAR Buffer = 0;
  278. DWORD dwBytesOut = 0;
  279. if (!DeviceIoControl(NbtHandle,
  280. IOCTL_NETBT_PURGE_CACHE,
  281. NULL,
  282. 0,
  283. &Buffer,
  284. 1,
  285. &dwBytesOut,
  286. NULL))
  287. {
  288. hr = HRESULT_FROM_WIN32(GetLastError());
  289. }
  290. TraceError("PurgeNbt", hr);
  291. return hr;
  292. }
  293. //+---------------------------------------------------------------------------
  294. //
  295. // Function: ReleaseRefreshNetBt
  296. //
  297. // Purpose: release and then refresh the name on the WINS server
  298. //
  299. // Arguments: NbtHandle [in] handle of the Netbt driver
  300. //
  301. // Returns:
  302. //
  303. HRESULT ReleaseRefreshNetBt(HANDLE NbtHandle)
  304. {
  305. HRESULT hr = S_OK;
  306. CHAR Buffer = 0;
  307. DWORD dwBytesOut = 0;
  308. if (!DeviceIoControl(NbtHandle,
  309. IOCTL_NETBT_NAME_RELEASE_REFRESH,
  310. NULL,
  311. 0,
  312. &Buffer,
  313. 1,
  314. &dwBytesOut,
  315. NULL))
  316. {
  317. DWORD dwErr = GetLastError();
  318. //RELEASE_REFRESH can at most do every two minutes
  319. //So if the user perform 2 RELEASE_REFRESH within 2 minutes, the 2nd
  320. //one will fail with ERROR_SEM_TIMEOUT. We ignore this particular error
  321. if (ERROR_SEM_TIMEOUT != dwErr)
  322. {
  323. hr = HRESULT_FROM_WIN32(dwErr);
  324. }
  325. }
  326. TraceError("ReleaseRefreshNetBt", hr);
  327. return hr;
  328. }
  329. //+---------------------------------------------------------------------------
  330. //
  331. // Function: HrGetAdapterSettings
  332. //
  333. // Purpose: Query the stack to know whether dhcp is enabled
  334. //
  335. // Arguments: pszGuid [in] guid of the adapter
  336. // pfDhcp [out] contains whether dhcp is enabled
  337. // pdwIndex [out] contains the index of this adapter
  338. //
  339. // Returns:
  340. //
  341. HRESULT HrGetAdapterSettings(LPCWSTR pszGuid, BOOL * pfDhcp, DWORD * pdwIndex)
  342. {
  343. HRESULT hr = S_OK;
  344. PIP_ADAPTER_INFO pAdapterInfo = NULL;
  345. DWORD dwOutBufLen = 0;
  346. DWORD dwRet = ERROR_SUCCESS;
  347. Assert(pfDhcp);
  348. Assert(pszGuid);
  349. dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen);
  350. if (dwRet == ERROR_BUFFER_OVERFLOW)
  351. {
  352. pAdapterInfo = (PIP_ADAPTER_INFO) CoTaskMemAlloc(dwOutBufLen);
  353. if (NULL == pAdapterInfo)
  354. return E_OUTOFMEMORY;
  355. }
  356. else if (ERROR_SUCCESS == dwRet)
  357. {
  358. return E_FAIL;
  359. }
  360. else
  361. {
  362. return HRESULT_FROM_WIN32(dwRet);
  363. }
  364. dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen);
  365. if (ERROR_SUCCESS != dwRet)
  366. {
  367. CoTaskMemFree(pAdapterInfo);
  368. return HRESULT_FROM_WIN32(dwRet);
  369. }
  370. BOOL fFound = FALSE;
  371. PIP_ADAPTER_INFO pAdapterInfoEnum = pAdapterInfo;
  372. while (pAdapterInfoEnum)
  373. {
  374. USES_CONVERSION;
  375. if (lstrcmp(pszGuid, A2W(pAdapterInfoEnum->AdapterName)) == 0)
  376. {
  377. if (pdwIndex)
  378. {
  379. *pdwIndex = pAdapterInfoEnum->Index;
  380. }
  381. *pfDhcp = pAdapterInfoEnum->DhcpEnabled;
  382. fFound = TRUE;
  383. break;
  384. }
  385. pAdapterInfoEnum = pAdapterInfoEnum->Next;
  386. }
  387. CoTaskMemFree(pAdapterInfo);
  388. if (!fFound)
  389. {
  390. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  391. }
  392. return hr;
  393. }
  394. HRESULT RepairConnectionInternal(
  395. GUID & guidConnection,
  396. LPWSTR * ppszMessage)
  397. {
  398. if (NULL != ppszMessage &&
  399. IsBadWritePtr(ppszMessage, sizeof(LPWSTR)))
  400. {
  401. return E_INVALIDARG;
  402. }
  403. if (ppszMessage)
  404. {
  405. *ppszMessage = NULL;
  406. }
  407. if (!FHasPermission(NCPERM_Repair))
  408. {
  409. return E_ACCESSDENIED;
  410. }
  411. // Get the net connection manager
  412. CComPtr<INetConnectionManager> spConnMan;
  413. HRESULT hr = S_OK;
  414. hr = CoCreateInstance(CLSID_ConnectionManager, NULL,
  415. CLSCTX_ALL,
  416. IID_INetConnectionManager,
  417. (LPVOID *)&spConnMan);
  418. if (FAILED(hr))
  419. {
  420. return hr;
  421. }
  422. Assert(spConnMan.p);
  423. NcSetProxyBlanket(spConnMan);
  424. CComPtr<IEnumNetConnection> spEnum;
  425. hr = spConnMan->EnumConnections(NCME_DEFAULT, &spEnum);
  426. spConnMan = NULL;
  427. if (FAILED(hr))
  428. {
  429. return hr;
  430. }
  431. Assert(spEnum.p);
  432. BOOL fFound = FALSE;
  433. ULONG ulCount = 0;
  434. INetConnection * pConn = NULL;
  435. spEnum->Reset();
  436. do
  437. {
  438. NETCON_PROPERTIES* pProps = NULL;
  439. hr = spEnum->Next(1, &pConn, &ulCount);
  440. if (SUCCEEDED(hr) && 1 == ulCount)
  441. {
  442. NcSetProxyBlanket(pConn);
  443. hr = pConn->GetProperties(&pProps);
  444. if (S_OK == hr)
  445. {
  446. if (IsEqualGUID(pProps->guidId, guidConnection))
  447. {
  448. fFound = TRUE;
  449. //we only support LAN and Bridge adapters
  450. if (NCM_LAN != pProps->MediaType && NCM_BRIDGE != pProps->MediaType)
  451. {
  452. hr = CO_E_NOT_SUPPORTED;
  453. }
  454. break;
  455. }
  456. FreeNetconProperties(pProps);
  457. }
  458. pConn->Release();
  459. pConn = NULL;
  460. }
  461. }while (SUCCEEDED(hr) && 1 == ulCount);
  462. if (!fFound)
  463. {
  464. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  465. }
  466. if (FAILED(hr))
  467. {
  468. return hr;
  469. }
  470. LPWSTR psz = NULL;
  471. tstring strMessage;
  472. hr = HrTryToFix(guidConnection, strMessage);
  473. if (ppszMessage && S_OK != hr && strMessage.length())
  474. {
  475. psz = (LPWSTR) LocalAlloc(LPTR, (strMessage.length() + 1) * sizeof(WCHAR));
  476. lstrcpy(psz, strMessage.c_str());
  477. *ppszMessage = psz;
  478. }
  479. return hr;
  480. }
  481. //+---------------------------------------------------------------------------
  482. //
  483. // Function: HrRenewIPv6Interface
  484. //
  485. // Purpose: Let the interface re-do IPv6 autoconfiguration
  486. //
  487. // Arguments: pszGuid [in] guid of the adapter
  488. //
  489. // Returns: S_OK - succeed
  490. // S_FALSE - IPv6 is not running on the adapter
  491. // Otherwise, Failure code
  492. //
  493. HRESULT HrRenewIPv6Interface(const GUID & guidConnection)
  494. {
  495. HRESULT hr = S_OK;
  496. HANDLE hIp6Device = INVALID_HANDLE_VALUE;
  497. IPV6_QUERY_INTERFACE Query = {0};
  498. DWORD dwBytesReturned = 0;
  499. DWORD dwError = NO_ERROR;
  500. do
  501. {
  502. // We could make the hIp6Device handle a global/static variable.
  503. // The first successful call to CreateFileW in HrRenewIPv6Interface
  504. // would initialize it with a handle to the IPv6 Device. This would
  505. // be used for all subsequent DeviceIoControl requests.
  506. //
  507. // Since this function is not called in a thread safe environment,
  508. // we would need to perform an InterlockedCompareExchange after
  509. // calling CreateFileW. This is needed to ensure that no handles
  510. // are leaked. Also, since this service would have an open handle
  511. // to tcpip6.sys, we would not be able to unload that driver.
  512. //
  513. // For now, however, we keep things simple and open and close this
  514. // handle every time HrRenewIPv6Interface is called.
  515. hIp6Device = CreateFileW(
  516. WIN_IPV6_DEVICE_NAME,
  517. GENERIC_WRITE, // requires administrator privileges
  518. FILE_SHARE_READ | FILE_SHARE_WRITE,
  519. NULL, // security attributes
  520. OPEN_EXISTING,
  521. 0, // flags & attributes
  522. NULL); // template file
  523. if (hIp6Device == INVALID_HANDLE_VALUE)
  524. {
  525. dwError = GetLastError();
  526. TraceError ("HrRenewIPv6Interface: CreateFileW failed",
  527. HRESULT_FROM_WIN32(dwError));
  528. if (ERROR_FILE_NOT_FOUND == dwError)
  529. {
  530. //IPv6 is not installed. Set return value as S_FALSE
  531. hr = S_FALSE;
  532. }
  533. else
  534. {
  535. hr = HRESULT_FROM_WIN32(dwError);
  536. }
  537. break;
  538. }
  539. // Pretend as though the interface was reconnected. This causes
  540. // IPv6 to resend Router Solicitation|Advertisement, Multicast
  541. // Listener Discovery, and Duplicate Address Detection messages.
  542. Query.Index = 0;
  543. Query.Guid = guidConnection;
  544. if (!DeviceIoControl(
  545. hIp6Device,
  546. IOCTL_IPV6_RENEW_INTERFACE,
  547. &Query,
  548. sizeof Query,
  549. NULL,
  550. 0,
  551. &dwBytesReturned,
  552. NULL))
  553. {
  554. dwError = GetLastError();
  555. TraceError("HrRenewIPv6Interface: DeviceIoControl failed",
  556. HRESULT_FROM_WIN32(dwError));
  557. if (ERROR_INVALID_PARAMETER == dwError)
  558. {
  559. //IPv6 is not running on the interface. Set return value as S_FALSE
  560. hr = S_FALSE;
  561. }
  562. else
  563. {
  564. hr = HRESULT_FROM_WIN32(dwError);
  565. }
  566. break;
  567. }
  568. }
  569. while (FALSE);
  570. if (hIp6Device != INVALID_HANDLE_VALUE)
  571. {
  572. CloseHandle(hIp6Device);
  573. }
  574. return hr;
  575. }
  576. HRESULT HrRegisterIPv6Dns()
  577. {
  578. DWORD dwErr = NO_ERROR;
  579. SC_HANDLE hcm = NULL;
  580. SC_HANDLE hSvc = NULL;
  581. SERVICE_STATUS status = {0};
  582. HRESULT hr = S_OK;
  583. do
  584. {
  585. hcm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  586. if (NULL == hcm)
  587. {
  588. dwErr = GetLastError();
  589. break;
  590. }
  591. hSvc = OpenService(hcm, c_sz624svc, SERVICE_USER_DEFINED_CONTROL);
  592. if (NULL == hSvc)
  593. {
  594. dwErr = GetLastError();
  595. break;
  596. }
  597. if (!ControlService(hSvc, SERVICE_CONTROL_6TO4_REGISER_DNS, &status))
  598. {
  599. dwErr = GetLastError();
  600. break;
  601. }
  602. } while (FALSE);
  603. if (hSvc)
  604. {
  605. CloseServiceHandle(hSvc);
  606. }
  607. if (hcm)
  608. {
  609. CloseServiceHandle(hcm);
  610. }
  611. hr = (NO_ERROR == dwErr) ? S_OK : HRESULT_FROM_WIN32(dwErr);
  612. TraceError ("Repair: HrRegisterIPv6Dns", hr);
  613. return hr;
  614. }