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.

2023 lines
68 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997-2001.
  5. //
  6. // File: C O N M A N . C P P
  7. //
  8. // Contents: Connection manager.
  9. //
  10. // Notes:
  11. //
  12. // Author: shaunco 21 Sep 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <dbt.h>
  18. #include <ndisguid.h>
  19. #include "conman.h"
  20. // #include "dialup.h"
  21. #include "enum.h"
  22. #include "eventq.h"
  23. #include "ncnetcon.h"
  24. #include "ncreg.h"
  25. #include "nminit.h"
  26. #if DBG
  27. #include "ncras.h"
  28. #endif // DBG
  29. #include <wmium.h>
  30. #include "cmutil.h"
  31. #include <shlwapi.h>
  32. #include <shfolder.h>
  33. #include "cobase.h"
  34. #define SECURITY_WIN32
  35. #include <security.h>
  36. #include <wzcsvc.h>
  37. #include "rasuip.h"
  38. #include "cmdirect.h"
  39. bool operator < (const GUID& rguid1, const GUID& rguid2) throw()
  40. {
  41. return memcmp(&rguid1, &rguid2, sizeof(GUID)) < 0;
  42. }
  43. static const WCHAR c_szRegKeyClassManagers [] = L"System\\CurrentControlSet\\Control\\Network\\Connections";
  44. static const WCHAR c_szRegValClassManagers [] = L"ClassManagers";
  45. volatile CConnectionManager* CConnectionManager::g_pConMan = NULL;
  46. volatile BOOL CConnectionManager::g_fInUse = FALSE;
  47. bool operator == (const NETCON_PROPERTIES& rProps1, const NETCON_PROPERTIES& rProps2) throw()
  48. {
  49. return (IsEqualGUID(rProps1.clsidThisObject, rProps2.clsidThisObject) &&
  50. IsEqualGUID(rProps1.clsidUiObject, rProps2.clsidUiObject) &&
  51. (rProps1.dwCharacter == rProps2.dwCharacter) &&
  52. IsEqualGUID(rProps1.guidId, rProps2.guidId) &&
  53. (rProps1.MediaType == rProps2.MediaType) &&
  54. (rProps1.pszwDeviceName == rProps2.pszwDeviceName) &&
  55. (rProps1.pszwName == rProps2.pszwName) &&
  56. (rProps1.Status == rProps2.Status));
  57. }
  58. const DWORD MAX_DISABLE_EVENT_TIMEOUT = 0xFFFF;
  59. //static
  60. BOOL
  61. CConnectionManager::FHasActiveConnectionPoints () throw()
  62. {
  63. TraceFileFunc(ttidConman);
  64. BOOL fRet = FALSE;
  65. // Note our intent to use g_pConMan. We may find out that it is not
  66. // available for use, but setting g_fInUse to TRUE prevents FinalRelease
  67. // from allowing the object to be destroyed while we are using it.
  68. //
  69. g_fInUse = TRUE;
  70. // Save g_pConMan into a local variable since we have to test and use
  71. // it atomically. If we tested g_pConMan directly and then used it
  72. // directly, it may have been set to NULL by FinalRelease in between
  73. // our test and use. (Uh, which would be bad.)
  74. //
  75. // The const_cast is because g_pConMan is declared volatile.
  76. //
  77. CConnectionManager* pConMan = const_cast<CConnectionManager*>(g_pConMan);
  78. if (pConMan)
  79. {
  80. pConMan->Lock();
  81. IUnknown** ppUnk;
  82. for (ppUnk = pConMan->m_vec.begin();
  83. ppUnk < pConMan->m_vec.end();
  84. ppUnk++)
  85. {
  86. if (ppUnk && *ppUnk)
  87. {
  88. fRet = TRUE;
  89. break;
  90. }
  91. }
  92. pConMan->Unlock();
  93. }
  94. // Now that we are finished using the object, indicate so. FinalRelease
  95. // may be waiting for this condition in which case the object will soon
  96. // be destroyed.
  97. //
  98. g_fInUse = FALSE;
  99. return fRet;
  100. }
  101. //+---------------------------------------------------------------------------
  102. //
  103. // Member: CConnectionManager::FinalRelease
  104. //
  105. // Purpose: COM destructor
  106. //
  107. // Arguments:
  108. // (none)
  109. //
  110. // Returns: nothing
  111. //
  112. // Author: shaunco 21 Sep 1997
  113. //
  114. // Notes:
  115. //
  116. VOID
  117. CConnectionManager::FinalRelease ()
  118. {
  119. TraceFileFunc(ttidConman);
  120. // Use INVALID_HANDLE_VALUE to block call until all outstanding event notifications have returned
  121. NTSTATUS Status = RtlDeregisterWaitEx(m_hRegNotifyWait, INVALID_HANDLE_VALUE);
  122. if (!NT_SUCCESS(Status))
  123. {
  124. TraceError("Could not deregister Registry Change Notification", HrFromLastWin32Error());
  125. }
  126. m_hRegNotifyWait = NULL;
  127. if (m_hRegClassManagerKey)
  128. {
  129. RegCloseKey(m_hRegClassManagerKey);
  130. m_hRegClassManagerKey = NULL;
  131. }
  132. if (m_hRegNotify)
  133. {
  134. CloseHandle(m_hRegNotify);
  135. m_hRegNotify = NULL;
  136. }
  137. // Unregister for PnP device events if we successfully registered for
  138. // them.
  139. //
  140. if (m_hDevNotify)
  141. {
  142. TraceTag (ttidConman, "Calling UnregisterDeviceNotification...");
  143. if (!UnregisterDeviceNotification (m_hDevNotify))
  144. {
  145. TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
  146. "UnregisterDeviceNotification");
  147. }
  148. }
  149. (VOID) HrEnsureRegisteredOrDeregisteredWithWmi (FALSE);
  150. // Revoke the global connection manager pointer so that subsequent calls
  151. // to NotifyClientsOfEvent on other threads will do nothing.
  152. //
  153. g_pConMan = NULL;
  154. // Wait for g_fInUse to become FALSE. NotifyClientsOfEvent will set
  155. // this to TRUE while it is using us.
  156. // Keep track of the number of times we sleep and trace it for
  157. // informational purposes. If we see that we are waiting quite a few
  158. // number of times, increase the wait period.
  159. //
  160. #ifdef ENABLETRACE
  161. if (g_fInUse)
  162. {
  163. TraceTag (ttidConman, "CConnectionManager::FinalRelease is waiting "
  164. "for NotifyClientsOfEvent to finish...");
  165. }
  166. #endif
  167. ULONG cSleeps = 0;
  168. const DWORD nMilliseconds = 0;
  169. while (g_fInUse)
  170. {
  171. cSleeps++;
  172. Sleep (nMilliseconds);
  173. }
  174. #ifdef ENABLETRACE
  175. if (cSleeps)
  176. {
  177. TraceTag (ttidConman, "CConnectionManager::FinalRelease slept %d "
  178. "times. (%d ms each time.)",
  179. cSleeps, nMilliseconds);
  180. }
  181. #endif
  182. // Release our class managers.
  183. //
  184. for (CLASSMANAGERMAP::iterator iter = m_mapClassManagers.begin(); iter != m_mapClassManagers.end(); iter++)
  185. {
  186. ReleaseObj (iter->second);
  187. }
  188. TraceTag (ttidConman, "Connection manager being destroyed");
  189. }
  190. inline
  191. LPVOID OffsetToPointer(LPVOID pStart, DWORD dwNumBytes)
  192. {
  193. DWORD_PTR dwPtr;
  194. dwPtr = reinterpret_cast<DWORD_PTR>(pStart);
  195. dwPtr += dwNumBytes;
  196. return reinterpret_cast<LPVOID>(dwPtr);
  197. }
  198. //+---------------------------------------------------------------------------
  199. //
  200. // Member: WmiEventCallback
  201. //
  202. // Purpose: Our WMI callback function that is called when WMI events are
  203. // received. This is registered using
  204. // CConnectionManager::HrEnsureRegisteredOrDeregisteredWithWmi
  205. //
  206. // Arguments:
  207. // Wnone [in]
  208. // NotificationContext [in]
  209. //
  210. // Returns: nothing
  211. //
  212. // Author: ckotze 2001
  213. //
  214. // Notes: Must match type of NOTIFICATIONCALLBACK
  215. //
  216. VOID
  217. WINAPI
  218. WmiEventCallback (
  219. PWNODE_HEADER Wnode,
  220. UINT_PTR NotificationContext)
  221. {
  222. TraceTag (ttidConman, "WmiEventCallback called...");
  223. TraceTag(ttidEvents, "Flags: %d", Wnode->Flags);
  224. if (WNODE_FLAG_SINGLE_INSTANCE == (WNODE_FLAG_SINGLE_INSTANCE & Wnode->Flags))
  225. {
  226. PWNODE_SINGLE_INSTANCE pInstance = reinterpret_cast<PWNODE_SINGLE_INSTANCE>(Wnode);
  227. LPCWSTR lpszDevice = NULL;
  228. LPWSTR lpszGuid;
  229. GUID guidAdapter;
  230. lpszDevice = reinterpret_cast<LPCWSTR>(OffsetToPointer(pInstance, pInstance->DataBlockOffset));
  231. lpszGuid = wcsrchr(lpszDevice, L'{');
  232. TraceTag(ttidEvents, "Adapter Guid From NDIS for Media Status Change Event: %S", lpszGuid);
  233. if (SUCCEEDED(CLSIDFromString(lpszGuid, &guidAdapter)))
  234. {
  235. CONMAN_EVENT* pEvent;
  236. pEvent = new CONMAN_EVENT;
  237. if(pEvent)
  238. {
  239. pEvent->ConnectionManager = CONMAN_LAN;
  240. pEvent->guidId = guidAdapter;
  241. pEvent->Type = CONNECTION_STATUS_CHANGE;
  242. if (IsEqualGUID(Wnode->Guid, GUID_NDIS_STATUS_MEDIA_CONNECT))
  243. {
  244. pEvent->Status = NCS_CONNECTED;
  245. }
  246. else if (IsEqualGUID(Wnode->Guid, GUID_NDIS_STATUS_MEDIA_DISCONNECT))
  247. {
  248. pEvent->Status = NCS_MEDIA_DISCONNECTED;
  249. }
  250. else
  251. {
  252. AssertSz(FALSE, "We never registered for this event ... WMI may be having internal issues.");
  253. MemFree(pEvent);
  254. return;
  255. }
  256. if (!QueueUserWorkItemInThread(LanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  257. {
  258. FreeConmanEvent(pEvent);
  259. }
  260. }
  261. }
  262. }
  263. else
  264. {
  265. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  266. }
  267. }
  268. //+---------------------------------------------------------------------------
  269. //
  270. // Member: CConnectionManager::HrEnsureRegisteredOrDeregisteredWithWmi
  271. //
  272. // Purpose: Register or deregister for NDIS Media Connect & Disconnect
  273. // with WMI
  274. //
  275. // Arguments:
  276. // fRegister [in] TRUE to register, FALSE to deregister
  277. //
  278. // Returns: nothing
  279. //
  280. // Author: ckotze 2001
  281. //
  282. // Notes:
  283. //
  284. HRESULT
  285. CConnectionManager::HrEnsureRegisteredOrDeregisteredWithWmi (
  286. IN BOOL fRegister)
  287. {
  288. TraceFileFunc(ttidConman);
  289. // Already registered or deregistered?
  290. //
  291. if (!!m_fRegisteredWithWmi == !!fRegister)
  292. {
  293. return S_OK;
  294. }
  295. m_fRegisteredWithWmi = !!fRegister;
  296. HRESULT hr = S_OK;
  297. DWORD dwErr;
  298. INT i;
  299. const GUID* apguid [] =
  300. {
  301. &GUID_NDIS_STATUS_MEDIA_CONNECT,
  302. &GUID_NDIS_STATUS_MEDIA_DISCONNECT,
  303. };
  304. TraceTag (ttidConman,
  305. "Calling WmiNotificationRegistration to %s for NDIS media events...",
  306. (fRegister) ? "register" : "unregister");
  307. for (i = 0; i < celems(apguid); i++)
  308. {
  309. dwErr = WmiNotificationRegistration (
  310. const_cast<GUID*>(apguid[i]),
  311. !!fRegister, // !! for BOOL to BOOLEAN
  312. WmiEventCallback,
  313. 0,
  314. NOTIFICATION_CALLBACK_DIRECT);
  315. hr = HRESULT_FROM_WIN32 (dwErr);
  316. TraceHr (ttidError, FAL, hr, FALSE, "WmiNotificationRegistration");
  317. }
  318. TraceHr (ttidError, FAL, hr, FALSE, "HrEnsureRegisteredOrDeregisteredWithWmi");
  319. return hr;
  320. }
  321. //+---------------------------------------------------------------------------
  322. //
  323. // Member: CConnectionManager::NotifyClientsOfEvent
  324. //
  325. // Purpose: Notify our connection points that this object has changed
  326. // state in some way and that a re-enumeration is needed.
  327. //
  328. // Arguments:
  329. // pEvent [in] The event to dispatch to all the clients
  330. //
  331. // Returns: nothing
  332. //
  333. // Author: shaunco 20 Mar 1998
  334. //
  335. // Notes: This is a static function. No this pointer is passed.
  336. //
  337. // static
  338. VOID CConnectionManager::NotifyClientsOfEvent (
  339. IN const CONMAN_EVENT* pEvent) throw()
  340. {
  341. TraceFileFunc(ttidConman);
  342. HRESULT hr;
  343. // Let's be sure we only do work if the service state is still running.
  344. // If we have a stop pending for example, we don't need to do anything.
  345. //
  346. if (SERVICE_RUNNING != _Module.DwServiceStatus ())
  347. {
  348. return;
  349. }
  350. // Note our intent to use g_pConMan. We may find out that it is not
  351. // available for use, but setting g_fInUse to TRUE prevents FinalRelease
  352. // from allowing the object to be destroyed while we are using it.
  353. //
  354. g_fInUse = TRUE;
  355. // Save g_pConMan into a local variable since we have to test and use
  356. // it atomically. If we tested g_pConMan directly and then used it
  357. // directly, it may have been set to NULL by FinalRelease in between
  358. // our test and use. (Uh, which would be bad.)
  359. //
  360. // The const_cast is because g_pConMan is declared volatile.
  361. //
  362. CConnectionManager* pConMan = const_cast<CConnectionManager*>(g_pConMan);
  363. if (pConMan)
  364. {
  365. ULONG cpUnk;
  366. IUnknown** apUnk;
  367. hr = HrCopyIUnknownArrayWhileLocked (
  368. pConMan,
  369. &pConMan->m_vec,
  370. &cpUnk,
  371. &apUnk);
  372. if (SUCCEEDED(hr) && cpUnk && apUnk)
  373. {
  374. #ifdef DBG
  375. CHAR szClientList[MAX_PATH];
  376. ZeroMemory(szClientList, MAX_PATH);
  377. LPSTR pszClientList = szClientList;
  378. ITERUSERNOTIFYMAP iter;
  379. for (iter = pConMan->m_mapNotify.begin(); iter != pConMan->m_mapNotify.end(); iter++)
  380. {
  381. pszClientList += sprintf(pszClientList, "%d ", iter->second->dwCookie);
  382. if (pszClientList > (szClientList + MAX_PATH-50) )
  383. {
  384. break;
  385. }
  386. }
  387. if (iter != pConMan->m_mapNotify.end())
  388. {
  389. pszClientList += sprintf(pszClientList, "(more)");
  390. }
  391. TraceTag (ttidConman,
  392. "NotifyClientsOfEvent: Notifying %d clients. Cookies: %s)",
  393. cpUnk, szClientList);
  394. #endif
  395. for (ULONG i = 0; i < cpUnk; i++)
  396. {
  397. INetConnectionNotifySink* pSink = NULL;
  398. BOOL fFireEventOnSink = FALSE;
  399. hr = apUnk[i]->QueryInterface(IID_INetConnectionNotifySink, reinterpret_cast<LPVOID*>(&pSink));
  400. ReleaseObj(apUnk[i]);
  401. if (SUCCEEDED(hr))
  402. {
  403. hr = CoSetProxyBlanket (
  404. pSink,
  405. RPC_C_AUTHN_WINNT, // use NT default security
  406. RPC_C_AUTHZ_NONE, // use NT default authentication
  407. NULL, // must be null if default
  408. RPC_C_AUTHN_LEVEL_CALL, // call
  409. RPC_C_IMP_LEVEL_IDENTIFY,
  410. NULL, // use process token
  411. EOAC_DEFAULT);
  412. if (SUCCEEDED(hr))
  413. {
  414. switch (pEvent->Type)
  415. {
  416. case CONNECTION_ADDED:
  417. Assert (pEvent);
  418. Assert (pEvent->pPropsEx);
  419. TraceTag(ttidEvents, "Characteristics: %s", DbgNccf(pEvent->pPropsEx->dwCharacter));
  420. if (!(NCCF_ALL_USERS == (pEvent->pPropsEx->dwCharacter & NCCF_ALL_USERS)))
  421. {
  422. const WCHAR* pchw = reinterpret_cast<const WCHAR*>(pEvent->pPropsEx->bstrPersistData);
  423. const WCHAR* pchwMax;
  424. PCWSTR pszwPhonebook;
  425. WCHAR LeadWord = PersistDataLead;
  426. WCHAR TrailWord = PersistDataTrail;
  427. IUnknown* pUnkSink = NULL;
  428. hr = pSink->QueryInterface(IID_IUnknown, reinterpret_cast<LPVOID*>(&pUnkSink));
  429. AssertSz(SUCCEEDED(hr), "Please explain how this happened...");
  430. if (SUCCEEDED(hr))
  431. {
  432. // The last valid pointer for the embedded strings.
  433. //
  434. pchwMax = reinterpret_cast<const WCHAR*>(pEvent->pbPersistData + pEvent->cbPersistData
  435. - (sizeof (GUID) +
  436. sizeof (BOOL) +
  437. sizeof (TrailWord)));
  438. if (pchw && (LeadWord == *pchw))
  439. {
  440. TraceTag(ttidEvents, "Found Correct Lead Character.");
  441. // Skip past our lead byte.
  442. //
  443. pchw++;
  444. // Get PhoneBook path. Search for the terminating null and make sure
  445. // we find it before the end of the buffer. Using lstrlen to skip
  446. // the string can result in an an AV in the event the string is
  447. // not actually null-terminated.
  448. //
  449. for (pszwPhonebook = pchw; *pchw != L'\0' ; pchw++)
  450. {
  451. if (pchw >= pchwMax)
  452. {
  453. pszwPhonebook = NULL;
  454. break;
  455. }
  456. }
  457. TraceTag(ttidEvents, "Found Valid Phonebook: %S", (pszwPhonebook) ? L"TRUE" : L"FALSE");
  458. if (pszwPhonebook)
  459. {
  460. pConMan->Lock();
  461. ITERUSERNOTIFYMAP iter = pConMan->m_mapNotify.find(pUnkSink);
  462. if (iter != pConMan->m_mapNotify.end())
  463. {
  464. tstring& strUserDataPath = iter->second->szUserProfilesPath;
  465. TraceTag(ttidEvents, "Comparing stored Path: %S to Phonebook Path: %S",
  466. strUserDataPath.c_str(), pszwPhonebook);
  467. if (_wcsnicmp(pszwPhonebook, strUserDataPath.c_str(), strUserDataPath.length()) == 0)
  468. {
  469. fFireEventOnSink = TRUE;
  470. }
  471. }
  472. else
  473. {
  474. TraceTag(ttidError, "Could not find Path for NotifySink: 0x%08x", pUnkSink);
  475. }
  476. pConMan->Unlock();
  477. }
  478. }
  479. else
  480. {
  481. // Some other devices do not use this Format, but need to be sent events.
  482. fFireEventOnSink = TRUE;
  483. }
  484. ReleaseObj(pUnkSink);
  485. }
  486. }
  487. else
  488. {
  489. TraceTag(ttidEvents, "All User Connection");
  490. fFireEventOnSink = TRUE;
  491. }
  492. if (fFireEventOnSink)
  493. {
  494. TraceTag (ttidEvents,
  495. "Notifying ConnectionAdded... (pSink=0x%p)",
  496. pSink);
  497. hr = pSink->ConnectionAdded (
  498. pEvent->pPropsEx);
  499. }
  500. break;
  501. case CONNECTION_BANDWIDTH_CHANGE:
  502. TraceTag (ttidEvents,
  503. "Notifying ConnectionBandWidthChange... (pSink=0x%p)",
  504. pSink);
  505. hr = pSink->ConnectionBandWidthChange (&pEvent->guidId);
  506. break;
  507. case CONNECTION_DELETED:
  508. TraceTag (ttidEvents,
  509. "Notifying ConnectionDeleted... (pSink=0x%p)",
  510. pSink);
  511. hr = pSink->ConnectionDeleted (&pEvent->guidId);
  512. break;
  513. case CONNECTION_MODIFIED:
  514. Assert (pEvent->pPropsEx);
  515. TraceTag (ttidEvents,
  516. "Notifying ConnectionModified... (pSink=0x%p)",
  517. pSink);
  518. hr = pSink->ConnectionModified (pEvent->pPropsEx);
  519. break;
  520. case CONNECTION_RENAMED:
  521. TraceTag (ttidEvents,
  522. "Notifying ConnectionRenamed... (pSink=0x%p)",
  523. pSink);
  524. hr = pSink->ConnectionRenamed (&pEvent->guidId,
  525. pEvent->szNewName);
  526. break;
  527. case CONNECTION_STATUS_CHANGE:
  528. TraceTag (ttidEvents,
  529. "Notifying ConnectionStatusChange... (pSink=0x%p)",
  530. pSink);
  531. TraceTag(ttidEvents, "Status changed to: %s", DbgNcs(pEvent->Status));
  532. hr = pSink->ConnectionStatusChange (&pEvent->guidId,
  533. pEvent->Status);
  534. break;
  535. case REFRESH_ALL:
  536. TraceTag (ttidEvents,
  537. "Notifying RefreshAll... (pSink=0x%p)",
  538. pSink);
  539. hr = pSink->RefreshAll ();
  540. break;
  541. case CONNECTION_ADDRESS_CHANGE:
  542. TraceTag (ttidEvents,
  543. "Notifying ConnectionAddressChange... (pSink=0x%p)",
  544. pSink);
  545. hr = pSink->ConnectionAddressChange(&pEvent->guidId);
  546. break;
  547. case CONNECTION_BALLOON_POPUP:
  548. TraceTag (ttidEvents,
  549. "Notifying ConnectionStatusChange... (pSink=0x%p)",
  550. pSink);
  551. hr = pSink->ShowBalloon(&pEvent->guidId, pEvent->szCookie, pEvent->szBalloonText);
  552. break;
  553. case DISABLE_EVENTS:
  554. TraceTag (ttidEvents,
  555. "Notifying DisableEvents... (pSink=0x%p)",
  556. pSink);
  557. hr = pSink->DisableEvents(pEvent->fDisable, pEvent->ulDisableTimeout);
  558. break;
  559. default:
  560. TraceTag(ttidEvents, "Event Type Passed: %d", pEvent->Type);
  561. AssertSz (FALSE, "Invalid Type specified in pEvent");
  562. break;
  563. }
  564. TraceErrorOptional("pSink call failed: ", hr, (S_FALSE == hr) );
  565. if ( (HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) == hr) ||
  566. (HRESULT_FROM_WIN32(RPC_S_CALL_FAILED_DNE) == hr) ||
  567. (RPC_E_SERVER_DIED == hr) ||
  568. (RPC_E_DISCONNECTED == hr) ||
  569. (HRESULT_FROM_WIN32(RPC_S_CALL_FAILED) == hr) )
  570. {
  571. IUnknown* pUnkSink = NULL;
  572. HRESULT hrT = pSink->QueryInterface(IID_IUnknown, reinterpret_cast<LPVOID*>(&pUnkSink));
  573. if (SUCCEEDED(hrT))
  574. {
  575. ITERUSERNOTIFYMAP iter = pConMan->m_mapNotify.find(pUnkSink);
  576. if (iter != pConMan->m_mapNotify.end())
  577. {
  578. TraceTag(ttidError, "Dead client detected. Removing notify advise for: %S", iter->second->szUserName.c_str());
  579. hrT = pConMan->Unadvise(iter->second->dwCookie);
  580. }
  581. ReleaseObj(pUnkSink);
  582. }
  583. TraceHr (ttidError, FAL, hrT, S_FALSE == hrT, "Error removing notify advise.");
  584. }
  585. }
  586. else
  587. {
  588. TraceHr (ttidError, FAL, hr, FALSE,
  589. "CConnectionManager::NotifyClientsOfEvent: "
  590. "CoSetProxyBlanket failed for event %d.",
  591. pEvent->Type);
  592. }
  593. ReleaseObj(pSink);
  594. }
  595. }
  596. MemFree (apUnk);
  597. }
  598. }
  599. // Now that we are finished using the object, indicate so. FinalRelease
  600. // may be waiting for this condition in which case the object will soon
  601. // be destroyed.
  602. //
  603. g_fInUse = FALSE;
  604. }
  605. //+---------------------------------------------------------------------------
  606. //
  607. // Member: CConnectionManager::HrEnsureClassManagersLoaded
  608. //
  609. // Purpose: Loads the class managers if they have not been loaded yet.
  610. //
  611. // Arguments:
  612. // (none)
  613. //
  614. // Returns: S_OK or an error code.
  615. //
  616. // Author: shaunco 10 Dec 1997
  617. //
  618. // Notes:
  619. //
  620. HRESULT
  621. CConnectionManager::HrEnsureClassManagersLoaded ()
  622. {
  623. TraceFileFunc(ttidConman);
  624. HRESULT hr = S_OK;
  625. // Need to protect m_mapClassManagers for the case that two clients
  626. // get our object simultaneously and call a method which invokes
  627. // this method. Need to transition m_mapClassManagers from being
  628. // empty to being full in one atomic operation.
  629. //
  630. CExceptionSafeComObjectLock EsLock (this);
  631. // If our vector of class managers is emtpy, try to load them.
  632. // This will certainly be the case if we haven't tried to load them yet.
  633. // If will also be the case when no class managers are registered.
  634. // This isn't likely because we register them in hivesys.inf, but it
  635. // shouldn't hurt to keep trying if they're really are none registered.
  636. //
  637. if (m_mapClassManagers.empty())
  638. {
  639. TraceTag (ttidConman, "Loading class managers...");
  640. // Load the registered class managers.
  641. //
  642. // Open the registry key where the class managers are registered.
  643. //
  644. HKEY hkey;
  645. hr = HrRegOpenKeyEx (HKEY_LOCAL_MACHINE,
  646. c_szRegKeyClassManagers, KEY_READ, &hkey);
  647. if (SUCCEEDED(hr))
  648. {
  649. // Read the multi-sz of class manager CLSIDs.
  650. //
  651. PWSTR pmsz;
  652. hr = HrRegQueryMultiSzWithAlloc (hkey, c_szRegValClassManagers,
  653. &pmsz);
  654. if (S_OK == hr)
  655. {
  656. (VOID) HrNmWaitForClassObjectsToBeRegistered ();
  657. // For each CLSID, create the object and request its
  658. // INetConnectionManager interface.
  659. //
  660. for (PCWSTR pszClsid = pmsz;
  661. *pszClsid;
  662. pszClsid += wcslen (pszClsid) + 1)
  663. {
  664. // Convert the string to a CLSID. If it fails, skip it.
  665. //
  666. CLSID clsid;
  667. if (FAILED(CLSIDFromString ((LPOLESTR)pszClsid, &clsid)))
  668. {
  669. TraceTag (ttidConman, "Skipping bogus CLSID (%S)",
  670. pszClsid);
  671. continue;
  672. }
  673. // Create the class manager and add it to our list.
  674. //
  675. INetConnectionManager* pConMan;
  676. hr = CoCreateInstance (
  677. clsid, NULL,
  678. CLSCTX_ALL | CLSCTX_NO_CODE_DOWNLOAD,
  679. IID_INetConnectionManager,
  680. reinterpret_cast<VOID**>(&pConMan));
  681. TraceHr (ttidError, FAL, hr, FALSE,
  682. "CConnectionManager::HrEnsureClassManagersLoaded: "
  683. "CoCreateInstance failed for class manager %S.",
  684. pszClsid);
  685. if (SUCCEEDED(hr))
  686. {
  687. TraceTag (ttidConman, "Loaded class manager %S",
  688. pszClsid);
  689. Assert (pConMan);
  690. if (m_mapClassManagers.find(clsid) != m_mapClassManagers.end())
  691. {
  692. AssertSz(FALSE, "Attempting to insert the same class manager twice!");
  693. }
  694. else
  695. {
  696. m_mapClassManagers[clsid] = pConMan;
  697. }
  698. }
  699. /*
  700. // If CoCreateInstance starts failing again on retail builds, this can
  701. // be helpful.
  702. else
  703. {
  704. CHAR psznBuf [512];
  705. wsprintfA (psznBuf, "NETCFG: CoCreateInstance failed "
  706. "(0x%08x) on class manager %i.\n",
  707. hr, m_mapClassManagers.size ());
  708. OutputDebugStringA (psznBuf);
  709. }
  710. */
  711. }
  712. MemFree (pmsz);
  713. }
  714. RegCloseKey (hkey);
  715. }
  716. TraceTag (ttidConman, "Loaded %i class managers",
  717. m_mapClassManagers.size ());
  718. }
  719. TraceErrorOptional ("CConnectionManager::HrEnsureClassManagersLoaded", hr, (S_FALSE == hr));
  720. return hr;
  721. }
  722. //+---------------------------------------------------------------------------
  723. //
  724. // Member: CConnectionManager::RegChangeNotifyHandler
  725. //
  726. // Purpose: Notification of a change inside the Registry where the
  727. // class managers clsid's are being stored. This updates the
  728. // class manager context with the new clsid's and send out a refresh
  729. // to all the clients.
  730. //
  731. // Arguments:
  732. // pContext [in,out] CConnectionManager context to update
  733. // fTimerFired [in] TRUE if this was as a result of a timeout
  734. //
  735. // Returns: VOID
  736. //
  737. // Author: deonb Feb 2002
  738. //
  739. // Notes: The pContext connection manager will be updated by the new
  740. // class manager in the registry, or the one just removed.
  741. //
  742. VOID NTAPI CConnectionManager::RegChangeNotifyHandler(IN OUT LPVOID pContext, IN BOOLEAN fTimerFired) throw()
  743. {
  744. TraceFileFunc(ttidConman);
  745. TraceTag(ttidConman, "CConnectionManager::RegChangeNotifyHandler (%d)", fTimerFired);
  746. CConnectionManager *pThis = reinterpret_cast<CConnectionManager *>(pContext);
  747. CExceptionSafeComObjectLock EsLock (pThis);
  748. list<GUID> lstRegisteredGuids;
  749. HKEY hkey;
  750. HRESULT hr = HrRegOpenKeyEx (HKEY_LOCAL_MACHINE, c_szRegKeyClassManagers, KEY_READ, &hkey);
  751. if (SUCCEEDED(hr))
  752. {
  753. // Read the multi-sz of class manager CLSIDs.
  754. //
  755. PWSTR pmsz;
  756. hr = HrRegQueryMultiSzWithAlloc (hkey, c_szRegValClassManagers,
  757. &pmsz);
  758. if (S_OK == hr)
  759. {
  760. for (PCWSTR pszClsid = pmsz;
  761. *pszClsid;
  762. pszClsid += wcslen (pszClsid) + 1)
  763. {
  764. CLSID clsid;
  765. if (FAILED(CLSIDFromString ((LPOLESTR)pszClsid, &clsid)))
  766. {
  767. TraceTag (ttidConman, "Skipping bogus CLSID (%S)", pszClsid);
  768. continue;
  769. }
  770. lstRegisteredGuids.push_back(clsid);
  771. }
  772. }
  773. RegCloseKey(hkey);
  774. BOOL bFound;
  775. do
  776. {
  777. bFound = FALSE;
  778. CLASSMANAGERMAP::iterator iterClassMgr;
  779. for (iterClassMgr = pThis->m_mapClassManagers.begin(); iterClassMgr != pThis->m_mapClassManagers.end(); iterClassMgr++)
  780. {
  781. if (find(lstRegisteredGuids.begin(), lstRegisteredGuids.end(), iterClassMgr->first) == lstRegisteredGuids.end())
  782. {
  783. // Class manager key has been removed
  784. TraceTag(ttidConman, "Removing class manager");
  785. bFound = TRUE;
  786. break;
  787. }
  788. }
  789. if (bFound)
  790. {
  791. ULONG uRefCount = iterClassMgr->second->Release();
  792. TraceTag(ttidConman, "Releasing class manager - Refcount = %d", uRefCount);
  793. pThis->m_mapClassManagers.erase(iterClassMgr);
  794. }
  795. } while (bFound);
  796. for (list<GUID>::iterator iter = lstRegisteredGuids.begin(); iter != lstRegisteredGuids.end(); iter++)
  797. {
  798. if (pThis->m_mapClassManagers.find(*iter) == pThis->m_mapClassManagers.end())
  799. {
  800. // Class manager key has been added
  801. TraceTag(ttidConman, "Adding class manager");
  802. INetConnectionManager* pConMan;
  803. hr = CoCreateInstance (
  804. *iter,
  805. NULL,
  806. CLSCTX_ALL | CLSCTX_NO_CODE_DOWNLOAD,
  807. IID_INetConnectionManager,
  808. reinterpret_cast<VOID**>(&pConMan));
  809. TraceHr (ttidError, FAL, hr, FALSE,
  810. "CConnectionManager::RegChangeNotifyHandler: CoCreateInstance failed for class manager.");
  811. if (SUCCEEDED(hr))
  812. {
  813. TraceTag (ttidConman, "Loaded class manager");
  814. Assert (pConMan);
  815. if (pThis->m_mapClassManagers.find(*iter) != pThis->m_mapClassManagers.end())
  816. {
  817. AssertSz(FALSE, "Attempting to insert the same class manager twice!");
  818. }
  819. else
  820. {
  821. pThis->m_mapClassManagers[*iter] = pConMan;
  822. }
  823. }
  824. }
  825. }
  826. }
  827. else
  828. {
  829. TraceError("Could not open registry key", HrFromLastWin32Error());
  830. }
  831. TraceError("RegChangeNotifyHandler", hr);
  832. // Update all the connection folder instances.
  833. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  834. // Reset the change notification
  835. RegNotifyChangeKeyValue(pThis->m_hRegClassManagerKey, FALSE, REG_NOTIFY_CHANGE_LAST_SET, pThis->m_hRegNotify, TRUE);
  836. }
  837. //+---------------------------------------------------------------------------
  838. // INetConnectionManager
  839. //
  840. //+---------------------------------------------------------------------------
  841. //
  842. // Member: CConnectionManager::EnumConnections
  843. //
  844. // Purpose: Return an INetConnection enumerator.
  845. //
  846. // Arguments:
  847. // Flags [in] Unused currently
  848. // ppEnum [out] The enumerator.
  849. //
  850. // Returns: S_OK or an error code.
  851. //
  852. // Author: shaunco 21 Sep 1997
  853. //
  854. // Notes:
  855. //
  856. STDMETHODIMP
  857. CConnectionManager::EnumConnections (
  858. IN NETCONMGR_ENUM_FLAGS Flags,
  859. OUT IEnumNetConnection** ppEnum)
  860. {
  861. TraceFileFunc(ttidConman);
  862. TraceTag(ttidConman, "CConnectionManager::EnumConnections (%d)", Flags);
  863. HRESULT hr = S_OK;
  864. {
  865. CExceptionSafeComObjectLock EsLock (this);
  866. Assert(FImplies(m_hRegNotify, m_hRegClassManagerKey));
  867. if (!m_hRegNotify)
  868. {
  869. m_hRegNotify = CreateEvent(NULL, FALSE, FALSE, NULL);
  870. if (m_hRegNotify)
  871. {
  872. NTSTATUS Status = RtlRegisterWait(&m_hRegNotifyWait, m_hRegNotify, &CConnectionManager::RegChangeNotifyHandler, this, INFINITE, WT_EXECUTEDEFAULT);
  873. if (!NT_SUCCESS(Status))
  874. {
  875. hr = HRESULT_FROM_NT(Status);
  876. }
  877. else
  878. {
  879. hr = HrRegOpenKeyEx (HKEY_LOCAL_MACHINE, c_szRegKeyClassManagers, KEY_READ, &m_hRegClassManagerKey);
  880. if (SUCCEEDED(hr))
  881. {
  882. hr = RegNotifyChangeKeyValue(m_hRegClassManagerKey, FALSE, REG_NOTIFY_CHANGE_LAST_SET, m_hRegNotify, TRUE);
  883. if (FAILED(hr))
  884. {
  885. RegCloseKey(m_hRegClassManagerKey);
  886. m_hRegClassManagerKey = NULL;
  887. }
  888. }
  889. if (FAILED(hr))
  890. {
  891. // Use INVALID_HANDLE_VALUE to block call until all outstanding event notifications have returned
  892. Status = RtlDeregisterWaitEx(m_hRegNotifyWait, INVALID_HANDLE_VALUE);
  893. if (!NT_SUCCESS(Status))
  894. {
  895. hr = HRESULT_FROM_NT(Status);
  896. }
  897. m_hRegNotifyWait = NULL;
  898. }
  899. }
  900. if (FAILED(hr))
  901. {
  902. CloseHandle(m_hRegNotify);
  903. m_hRegNotify = NULL;
  904. }
  905. }
  906. else
  907. {
  908. hr = HrFromLastWin32Error();
  909. }
  910. }
  911. if (SUCCEEDED(hr))
  912. {
  913. // Create and return the enumerator.
  914. //
  915. hr = HrEnsureClassManagersLoaded ();
  916. }
  917. if (SUCCEEDED(hr))
  918. {
  919. hr = CConnectionManagerEnumConnection::CreateInstance (
  920. Flags,
  921. m_mapClassManagers,
  922. IID_IEnumNetConnection,
  923. reinterpret_cast<VOID**>(ppEnum));
  924. }
  925. }
  926. TraceErrorOptional ("CConnectionManager::EnumConnections", hr, (S_FALSE == hr));
  927. return hr;
  928. }
  929. //+---------------------------------------------------------------------------
  930. // INetConnectionRefresh
  931. //
  932. STDMETHODIMP
  933. CConnectionManager::RefreshAll()
  934. {
  935. TraceFileFunc(ttidConman);
  936. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  937. return S_OK;
  938. }
  939. //+---------------------------------------------------------------------------
  940. //
  941. // Function: CConnectionManager::ConnectionAdded
  942. //
  943. // Purpose: Notifies event sinks that a new connection has been added.
  944. //
  945. // Arguments:
  946. // pConnection [in] INetConnection* for new connection.
  947. //
  948. // Returns: Standard HRESULT
  949. //
  950. // Author: deonb 22 Mar 2001
  951. //
  952. // Notes:
  953. //
  954. STDMETHODIMP
  955. CConnectionManager::ConnectionAdded(
  956. IN INetConnection* pConnection)
  957. {
  958. TraceFileFunc(ttidConman);
  959. HRESULT hr = S_OK;
  960. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  961. if (pEvent)
  962. {
  963. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  964. pEvent->Type = CONNECTION_ADDED;
  965. hr = HrGetPropertiesExFromINetConnection(pConnection, &pEvent->pPropsEx);
  966. if (SUCCEEDED(hr))
  967. {
  968. if (QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  969. {
  970. return hr;
  971. }
  972. hr = E_FAIL;
  973. }
  974. FreeConmanEvent(pEvent);
  975. }
  976. else
  977. {
  978. hr = E_OUTOFMEMORY;
  979. }
  980. return hr;
  981. }
  982. //+---------------------------------------------------------------------------
  983. //
  984. // Function: CConnectionManager::ConnectionDeleted
  985. //
  986. // Purpose: Sends an event to notify of a connection being deleted.
  987. //
  988. // Arguments:
  989. // pguidId [in] GUID of the connectoid
  990. //
  991. // Returns: Standard HRESULT
  992. //
  993. // Author: ckotze 18 Apr 2001
  994. //
  995. // Notes:
  996. //
  997. STDMETHODIMP
  998. CConnectionManager::ConnectionDeleted(
  999. IN const GUID* pguidId)
  1000. {
  1001. TraceFileFunc(ttidConman);
  1002. HRESULT hr = S_OK;
  1003. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1004. if (pEvent)
  1005. {
  1006. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1007. pEvent->Type = CONNECTION_DELETED;
  1008. pEvent->guidId = *pguidId;
  1009. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  1010. {
  1011. hr = E_FAIL;
  1012. FreeConmanEvent(pEvent);
  1013. }
  1014. }
  1015. else
  1016. {
  1017. hr = E_OUTOFMEMORY;
  1018. }
  1019. return hr;
  1020. }
  1021. //+---------------------------------------------------------------------------
  1022. //
  1023. // Function: CConnectionManager::ConnectionRenamed
  1024. //
  1025. // Purpose: Notifies the event sinks of a connection being renamed.
  1026. //
  1027. // Arguments:
  1028. // pConnection [in] INetConnection* for new connection.
  1029. //
  1030. // Returns: Standard HRESULT
  1031. //
  1032. // Author: ckotze 19 Apr 2001
  1033. //
  1034. // Notes:
  1035. //
  1036. STDMETHODIMP
  1037. CConnectionManager::ConnectionRenamed(
  1038. IN INetConnection* pConnection)
  1039. {
  1040. TraceFileFunc(ttidConman);
  1041. HRESULT hr = S_OK;
  1042. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1043. if (pEvent)
  1044. {
  1045. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1046. pEvent->Type = CONNECTION_RENAMED;
  1047. hr = HrGetPropertiesExFromINetConnection(pConnection, &pEvent->pPropsEx);
  1048. if (SUCCEEDED(hr))
  1049. {
  1050. lstrcpynW (pEvent->szNewName, pEvent->pPropsEx->bstrName, celems(pEvent->szNewName) );
  1051. pEvent->guidId = pEvent->pPropsEx->guidId;
  1052. if (QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  1053. {
  1054. return hr;
  1055. }
  1056. hr = E_FAIL;
  1057. }
  1058. FreeConmanEvent(pEvent);
  1059. }
  1060. else
  1061. {
  1062. hr = E_OUTOFMEMORY;
  1063. }
  1064. return hr;
  1065. }
  1066. //+---------------------------------------------------------------------------
  1067. //
  1068. // Function: CConnectionManager::ConnectionModified
  1069. //
  1070. // Purpose: Sends an event to notify clients that the connection has been
  1071. // Modified.
  1072. // Arguments:
  1073. // pConnection [in] INetConnection* for new connection.
  1074. //
  1075. // Returns: Standard HRESULT
  1076. //
  1077. // Author: ckotze 22 Mar 2001
  1078. //
  1079. // Notes:
  1080. //
  1081. STDMETHODIMP
  1082. CConnectionManager::ConnectionModified(INetConnection* pConnection)
  1083. {
  1084. TraceFileFunc(ttidConman);
  1085. HRESULT hr = S_OK;
  1086. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1087. if (pEvent)
  1088. {
  1089. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1090. pEvent->Type = CONNECTION_MODIFIED;
  1091. hr = HrGetPropertiesExFromINetConnection(pConnection, &pEvent->pPropsEx);
  1092. if (SUCCEEDED(hr))
  1093. {
  1094. if (QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  1095. {
  1096. return hr;
  1097. }
  1098. hr = E_FAIL;
  1099. }
  1100. FreeConmanEvent(pEvent);
  1101. }
  1102. else
  1103. {
  1104. hr = E_OUTOFMEMORY;
  1105. }
  1106. return hr;
  1107. }
  1108. //+---------------------------------------------------------------------------
  1109. //
  1110. // Function: CConnectionManager::ConnectionStatusChanged
  1111. //
  1112. // Purpose: Sends the ShowBalloon event to each applicable netshell
  1113. //
  1114. // Arguments:
  1115. // pguidId [in] GUID of the connectoid
  1116. // ncs [in] New status of the connectoid
  1117. //
  1118. // Returns: Standard HRESULT
  1119. //
  1120. // Author: deonb 22 Mar 2001
  1121. //
  1122. // Notes:
  1123. //
  1124. STDMETHODIMP
  1125. CConnectionManager::ConnectionStatusChanged(
  1126. IN const GUID* pguidId,
  1127. IN const NETCON_STATUS ncs)
  1128. {
  1129. TraceFileFunc(ttidConman);
  1130. HRESULT hr = S_OK;
  1131. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1132. if (pEvent)
  1133. {
  1134. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1135. pEvent->Type = CONNECTION_STATUS_CHANGE;
  1136. pEvent->guidId = *pguidId;
  1137. pEvent->Status = ncs;
  1138. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  1139. {
  1140. FreeConmanEvent(pEvent);
  1141. hr = E_FAIL;
  1142. }
  1143. }
  1144. else
  1145. {
  1146. hr = E_OUTOFMEMORY;
  1147. }
  1148. return hr;
  1149. }
  1150. //+---------------------------------------------------------------------------
  1151. //
  1152. // Function: CConnectionManager::ShowBalloon
  1153. //
  1154. // Purpose: Sends the ShowBalloon event to each applicable netshell
  1155. //
  1156. // Arguments:
  1157. // pguidId [in] GUID of the connectoid
  1158. // szCookie [in] A specified cookie that will end up at netshell
  1159. // szBalloonText [in] The balloon text
  1160. //
  1161. // Returns: Standard HRESULT
  1162. //
  1163. // Author: deonb 22 Mar 2001
  1164. //
  1165. // Notes:
  1166. //
  1167. STDMETHODIMP
  1168. CConnectionManager::ShowBalloon(
  1169. IN const GUID *pguidId,
  1170. IN const BSTR szCookie,
  1171. IN const BSTR szBalloonText)
  1172. {
  1173. TraceFileFunc(ttidConman);
  1174. HRESULT hr = S_OK;
  1175. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1176. if (pEvent)
  1177. {
  1178. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1179. pEvent->Type = CONNECTION_BALLOON_POPUP;
  1180. pEvent->guidId = *pguidId;
  1181. pEvent->szCookie = SysAllocStringByteLen(reinterpret_cast<LPCSTR>(szCookie), SysStringByteLen(szCookie));
  1182. pEvent->szBalloonText = SysAllocString(szBalloonText);
  1183. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  1184. {
  1185. hr = E_FAIL;
  1186. FreeConmanEvent(pEvent);
  1187. }
  1188. }
  1189. else
  1190. {
  1191. hr = E_OUTOFMEMORY;
  1192. }
  1193. return hr;
  1194. }
  1195. //+---------------------------------------------------------------------------
  1196. //
  1197. // Function: CConnectionManager::DisableEvents
  1198. //
  1199. // Purpose: Disable netshell processing of events for x milliseconds
  1200. //
  1201. // Arguments:
  1202. // fDisable [in] TRUE to disable EVENT processing, FALSE to renable
  1203. // ulDisableTimeout [in] Number of milliseconds to disable event processing for
  1204. //
  1205. // Returns: Standard HRESULT
  1206. //
  1207. // Author: deonb 10 April 2001
  1208. //
  1209. // Notes:
  1210. //
  1211. STDMETHODIMP CConnectionManager::DisableEvents(IN const BOOL fDisable, IN const ULONG ulDisableTimeout)
  1212. {
  1213. TraceFileFunc(ttidConman);
  1214. HRESULT hr = S_OK;
  1215. if (ulDisableTimeout > MAX_DISABLE_EVENT_TIMEOUT)
  1216. {
  1217. return E_INVALIDARG;
  1218. }
  1219. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1220. if (pEvent)
  1221. {
  1222. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1223. pEvent->Type = DISABLE_EVENTS;
  1224. pEvent->fDisable = fDisable;
  1225. // We set the high bit to let netshell know that this is coming from our private interface.
  1226. pEvent->ulDisableTimeout = 0x80000000 | ulDisableTimeout;
  1227. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  1228. {
  1229. hr = E_FAIL;
  1230. FreeConmanEvent(pEvent);
  1231. }
  1232. }
  1233. else
  1234. {
  1235. hr = E_OUTOFMEMORY;
  1236. }
  1237. return hr;
  1238. }
  1239. //+---------------------------------------------------------------------------
  1240. //
  1241. // Function: CConnectionManager::RefreshConnections
  1242. //
  1243. // Purpose: Refreshes the connections in the connections folder
  1244. //
  1245. // Arguments:
  1246. // None.
  1247. //
  1248. //
  1249. // Returns: Standard HRESULT
  1250. //
  1251. // Author: ckotze 19 April 2001
  1252. //
  1253. // Notes: This is a public interface that we are providing in order to
  1254. // allow other components/companies to have some control over
  1255. // the Connections Folder.
  1256. STDMETHODIMP CConnectionManager::RefreshConnections()
  1257. {
  1258. TraceFileFunc(ttidConman);
  1259. HRESULT hr = S_OK;
  1260. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1261. if (pEvent)
  1262. {
  1263. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1264. pEvent->Type = REFRESH_ALL;
  1265. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  1266. {
  1267. hr = E_FAIL;
  1268. FreeConmanEvent(pEvent);
  1269. }
  1270. }
  1271. else
  1272. {
  1273. hr = E_OUTOFMEMORY;
  1274. }
  1275. return hr;
  1276. }
  1277. //+---------------------------------------------------------------------------
  1278. //
  1279. // Function: CConnectionManager::Enable
  1280. //
  1281. // Purpose: Enables events to be fired once more in the connections folder
  1282. //
  1283. // Arguments:
  1284. // None.
  1285. //
  1286. // Returns: Standard HRESULT
  1287. //
  1288. // Author: ckotze 19 April 2001
  1289. //
  1290. // Notes: This is a public interface that we are providing in order to
  1291. // allow other components/companies to have some control over
  1292. // the Connections Folder.
  1293. // Since this is a public interface, we are only allowing the
  1294. // INVALID_ADDRESS notification to be disabled
  1295. // (this will take place in netshell.dll).
  1296. //
  1297. STDMETHODIMP CConnectionManager::Enable()
  1298. {
  1299. TraceFileFunc(ttidConman);
  1300. HRESULT hr = S_OK;
  1301. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1302. if (pEvent)
  1303. {
  1304. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1305. pEvent->Type = DISABLE_EVENTS;
  1306. pEvent->fDisable = FALSE;
  1307. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  1308. {
  1309. hr = E_FAIL;
  1310. FreeConmanEvent(pEvent);
  1311. }
  1312. }
  1313. else
  1314. {
  1315. hr = E_OUTOFMEMORY;
  1316. }
  1317. return hr;
  1318. }
  1319. //+---------------------------------------------------------------------------
  1320. //
  1321. // Function: CConnectionManager::Disable
  1322. //
  1323. // Purpose: Disable netshell processing of events for x milliseconds
  1324. //
  1325. // Arguments:
  1326. // ulDisableTimeout [in] Number of milliseconds to disable event
  1327. // processing for. Max is 60000 (1 minute)
  1328. //
  1329. // Returns: Standard HRESULT
  1330. //
  1331. // Author: ckotze 19 April 2001
  1332. //
  1333. // Notes: This is a public interface that we are providing in order to
  1334. // allow other components/companies to have some control over
  1335. // the Connections Folder.
  1336. // Since this is a public interface, we are only allowing the
  1337. // INVALID_ADDRESS notification to be disabled
  1338. // (this will take place in netshell.dll).
  1339. //
  1340. STDMETHODIMP CConnectionManager::Disable(IN const ULONG ulDisableTimeout)
  1341. {
  1342. TraceFileFunc(ttidConman);
  1343. HRESULT hr = S_OK;
  1344. if (ulDisableTimeout > MAX_DISABLE_EVENT_TIMEOUT)
  1345. {
  1346. return E_INVALIDARG;
  1347. }
  1348. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1349. if (pEvent)
  1350. {
  1351. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1352. pEvent->Type = DISABLE_EVENTS;
  1353. pEvent->fDisable = TRUE;
  1354. pEvent->ulDisableTimeout = ulDisableTimeout;
  1355. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  1356. {
  1357. hr = E_FAIL;
  1358. FreeConmanEvent(pEvent);
  1359. }
  1360. }
  1361. else
  1362. {
  1363. hr = E_OUTOFMEMORY;
  1364. }
  1365. return hr;
  1366. }
  1367. //+---------------------------------------------------------------------------
  1368. // INetConnectionCMUtil
  1369. //
  1370. //+---------------------------------------------------------------------------
  1371. //
  1372. // Function: MapCMHiddenConnectionToOwner
  1373. //
  1374. // Purpose: Maps a child connection to its parent connection.
  1375. //
  1376. // Connection Manager has two stages: Dialup and VPN.
  1377. // For the Dialup it creates a hidden connectoid that the
  1378. // folder (netshell) does not see. However netman caches
  1379. // the name, guid and status of this connectedoid. Both
  1380. // the parent and child connectoid have the same name. When
  1381. // the status of the hidden connectiod is updated the folder
  1382. // recives the guid of the hidden connectoid and maps the
  1383. // connectiod to it parent (Connection Manager) by searching
  1384. // netmans cache for the name of the hidden connectoid. Then it
  1385. // searches the connections in the folder for that name and thus
  1386. // gets the guid of the parent connectoid.
  1387. //
  1388. // When the folder gets a notify message from netman for the hidden
  1389. // connection it uses this function to find the parent and update the
  1390. // parent's status. The hidden connection is not displayed.
  1391. //
  1392. // Arguments:
  1393. // guidHidden [in] GUID of the hidden connectiod
  1394. // pguidOwner [out] GUID of the parent connectiod
  1395. //
  1396. // Returns: S_OK -- Found hidden connection
  1397. // else not found
  1398. //
  1399. // Author: omiller 1 Jun 2000
  1400. //
  1401. // Notes:
  1402. //
  1403. STDMETHODIMP
  1404. CConnectionManager::MapCMHiddenConnectionToOwner (
  1405. /*[in]*/ REFGUID guidHidden,
  1406. /*[out]*/ GUID * pguidOwner)
  1407. {
  1408. TraceFileFunc(ttidConman);
  1409. HRESULT hr = S_OK;
  1410. bool bFound = false;
  1411. hr = HrEnsureClassManagersLoaded ();
  1412. if (SUCCEEDED(hr))
  1413. {
  1414. // Impersonate the user so that we see all of the connections displayed in the folder
  1415. //
  1416. hr = CoImpersonateClient();
  1417. if (SUCCEEDED(hr))
  1418. {
  1419. // Find the hidden connection with this guid
  1420. //
  1421. CMEntry cm;
  1422. hr = CCMUtil::Instance().HrGetEntry(guidHidden, cm);
  1423. // Did we find the hidden connection?
  1424. if( S_OK == hr )
  1425. {
  1426. // Enumerate through all of the connections and find connection with the same name as the
  1427. // hidden connection
  1428. //
  1429. IEnumNetConnection * pEnum = NULL;
  1430. hr = CMDIRECT(DIALUP, CreateWanConnectionManagerEnumConnectionInstance)(NCME_DEFAULT, IID_IEnumNetConnection, reinterpret_cast<LPVOID *>(&pEnum));
  1431. if (SUCCEEDED(hr))
  1432. {
  1433. INetConnection * pNetCon;
  1434. NETCON_PROPERTIES * pProps;
  1435. while(!bFound)
  1436. {
  1437. // Get the nect connection
  1438. //
  1439. hr = pEnum->Next(1, &pNetCon, NULL);
  1440. if(S_OK != hr)
  1441. {
  1442. // Ooops encountered some error, stop searching
  1443. //
  1444. break;
  1445. }
  1446. // Get the properties of the connection
  1447. //
  1448. hr = pNetCon->GetProperties(&pProps);
  1449. if(SUCCEEDED(hr))
  1450. {
  1451. if(lstrcmp(cm.m_szEntryName, pProps->pszwName) == 0)
  1452. {
  1453. // Found the connection that has the same name a the hidden connection
  1454. // Stop searching!!
  1455. *pguidOwner = pProps->guidId;
  1456. bFound = true;
  1457. }
  1458. FreeNetconProperties(pProps);
  1459. }
  1460. ReleaseObj(pNetCon);
  1461. }
  1462. ReleaseObj(pEnum);
  1463. }
  1464. }
  1465. // Stop Impersonating the user
  1466. //
  1467. CoRevertToSelf();
  1468. }
  1469. }
  1470. return bFound ? S_OK : S_FALSE;
  1471. }
  1472. //+---------------------------------------------------------------------------
  1473. // IConnectionPoint overrides netman!CConnectionManager__Advise
  1474. //
  1475. STDMETHODIMP
  1476. CConnectionManager::Advise (
  1477. IUnknown* pUnkSink,
  1478. DWORD* pdwCookie)
  1479. {
  1480. HRESULT hr = S_OK;
  1481. TraceTag(ttidConman, "Advise");
  1482. Assert(!FBadInPtr(pUnkSink));
  1483. // Set our cloaked identity to be used when we call back on this
  1484. // advise interface. It's important to do this for security. Since
  1485. // we run as LocalSystem, if we were to call back without identify
  1486. // impersonation only, the client could impersonate us and get a free
  1487. // LocalSystem context which could be used for malicious purposes.
  1488. //
  1489. //
  1490. CoSetProxyBlanket (
  1491. pUnkSink,
  1492. RPC_C_AUTHN_WINNT, // use NT default security
  1493. RPC_C_AUTHZ_NONE, // use NT default authentication
  1494. NULL, // must be null if default
  1495. RPC_C_AUTHN_LEVEL_CALL, // call
  1496. RPC_C_IMP_LEVEL_IDENTIFY,
  1497. NULL, // use process token
  1498. EOAC_DEFAULT);
  1499. TraceHr(ttidError, FAL, hr, FALSE, "CoSetProxyBlanket");
  1500. if (S_OK == hr)
  1501. {
  1502. // Initialize our event handler if it has not already been done.
  1503. hr = HrEnsureEventHandlerInitialized();
  1504. if (SUCCEEDED(hr))
  1505. {
  1506. CComPtr<INetConnectionNotifySink> pNotifySink;
  1507. hr = pUnkSink->QueryInterface(IID_INetConnectionNotifySink, reinterpret_cast<void**>(&pNotifySink));
  1508. if (SUCCEEDED(hr))
  1509. {
  1510. GUID guidId = GUID_NULL;
  1511. // If either ConnectionStatusChange or ConnectionAddressChange is implemented, then we need to
  1512. // register with NLA for events.
  1513. if ((pNotifySink->ConnectionStatusChange(&guidId, NCS_CONNECTED) != E_NOTIMPL)
  1514. || (pNotifySink->ConnectionAddressChange(&guidId) != E_NOTIMPL))
  1515. {
  1516. // We still work for other events if this fails.
  1517. hr = HrEnsureRegisteredWithNla();
  1518. TraceErrorOptional("Could not register with Nla", hr, (S_FALSE == hr));
  1519. }
  1520. }
  1521. // Call the underlying ATL implementation of Advise.
  1522. //
  1523. hr = IConnectionPointImpl<
  1524. CConnectionManager,
  1525. &IID_INetConnectionNotifySink>::Advise(pUnkSink, pdwCookie);
  1526. TraceTag (ttidConman,
  1527. "CConnectionManager::Advise called... pUnkSink=0x%p, cookie=%d",
  1528. pUnkSink,
  1529. *pdwCookie);
  1530. TraceHr (ttidError, FAL, hr, FALSE, "IConnectionPointImpl::Advise");
  1531. if (SUCCEEDED(hr))
  1532. {
  1533. WCHAR szUserAppData[MAX_PATH];
  1534. HRESULT hrT = S_OK;
  1535. HRESULT hrImpersonate = S_OK;
  1536. if (SUCCEEDED(hrT))
  1537. {
  1538. // We ignore this HRESULT because we can be called inproc and that would definitely fail.
  1539. // Instead we just make sure that it succeeded when befor call CoRevertToSelf. This is
  1540. // fine because we'll still get a valid User App data path, it will just be something like
  1541. // LocalService or LocalSystem and we can still determine which sinks to send events to.
  1542. BOOLEAN fNotifyWZC = FALSE;
  1543. WCHAR szUserName[MAX_PATH];
  1544. CNotifySourceInfo* pNotifySourceInfo = new CNotifySourceInfo();
  1545. if (!pNotifySourceInfo)
  1546. {
  1547. hr = E_OUTOFMEMORY;
  1548. }
  1549. else
  1550. {
  1551. pNotifySourceInfo->dwCookie = *pdwCookie;
  1552. hrImpersonate = CoImpersonateClient();
  1553. if (SUCCEEDED(hrImpersonate) || (RPC_E_CALL_COMPLETE == hrImpersonate))
  1554. {
  1555. hrT = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szUserAppData);
  1556. if (SUCCEEDED(hrT))
  1557. {
  1558. pNotifySourceInfo->szUserProfilesPath = szUserAppData;
  1559. TraceTag(ttidEvents, "Adding IUnknown for Sink to Map: 0x%08x. Path: %S", reinterpret_cast<DWORD_PTR>(pUnkSink), szUserAppData);
  1560. TraceTag(ttidEvents, "Number of Items in Map: %d", m_mapNotify.size());
  1561. }
  1562. else
  1563. {
  1564. TraceError("Unable to get Folder Path", hrT);
  1565. }
  1566. ZeroMemory(szUserName, celems(szUserName));
  1567. ULONG nSize = celems(szUserName);
  1568. if (GetUserNameEx(NameSamCompatible, szUserName, &nSize) && *szUserName)
  1569. {
  1570. pNotifySourceInfo->szUserName = szUserName;
  1571. fNotifyWZC = TRUE;
  1572. }
  1573. else
  1574. {
  1575. pNotifySourceInfo->szUserName = L"System";
  1576. TraceError("Unable to get the user name", HrFromLastWin32Error());
  1577. }
  1578. }
  1579. Lock();
  1580. m_mapNotify[pUnkSink] = pNotifySourceInfo;
  1581. Unlock();
  1582. #ifdef DBG
  1583. LPWSTR* ppszAdviseUsers;
  1584. DWORD dwCount;
  1585. HRESULT hrT = GetClientAdvises(&ppszAdviseUsers, &dwCount);
  1586. if (SUCCEEDED(hrT))
  1587. {
  1588. Assert(dwCount);
  1589. TraceTag(ttidConman, "Advise client list after ::Advise:");
  1590. for (DWORD x = 0; x < dwCount; x++)
  1591. {
  1592. LPWSTR szUserName = ppszAdviseUsers[x];
  1593. TraceTag(ttidConman, "%x: %S", x, szUserName);
  1594. }
  1595. CoTaskMemFree(ppszAdviseUsers);
  1596. }
  1597. #endif
  1598. }
  1599. if (SUCCEEDED(hrImpersonate))
  1600. {
  1601. CoRevertToSelf();
  1602. }
  1603. if (fNotifyWZC)
  1604. {
  1605. WZCTrayIconReady(szUserName);
  1606. }
  1607. }
  1608. if (!m_lRegisteredOneTime)
  1609. {
  1610. // Do an explicit interlocked exchange to only let one thread
  1611. // through to do the registration.
  1612. //
  1613. if (0 == InterlockedExchange (&m_lRegisteredOneTime, 1))
  1614. {
  1615. // Register for device notifications. Specifically, we're
  1616. // interested in network adapters coming and going. If this
  1617. // fails, we proceed anyway.
  1618. //
  1619. TraceTag (ttidConman, "Calling RegisterDeviceNotification...");
  1620. DEV_BROADCAST_DEVICEINTERFACE PnpFilter;
  1621. ZeroMemory (&PnpFilter, sizeof(PnpFilter));
  1622. PnpFilter.dbcc_size = sizeof(PnpFilter);
  1623. PnpFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  1624. PnpFilter.dbcc_classguid = GUID_NDIS_LAN_CLASS;
  1625. m_hDevNotify = RegisterDeviceNotification (
  1626. (HANDLE)_Module.m_hStatus,
  1627. &PnpFilter,
  1628. DEVICE_NOTIFY_SERVICE_HANDLE);
  1629. if (!m_hDevNotify)
  1630. {
  1631. TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
  1632. "RegisterDeviceNotification");
  1633. }
  1634. (VOID) HrEnsureRegisteredOrDeregisteredWithWmi (TRUE);
  1635. }
  1636. }
  1637. }
  1638. }
  1639. }
  1640. TraceErrorOptional ("CConnectionManager::Advise", hr, (S_FALSE == hr));
  1641. return hr;
  1642. }
  1643. STDMETHODIMP
  1644. CConnectionManager::Unadvise(DWORD dwCookie)
  1645. {
  1646. HRESULT hr = S_OK;
  1647. TraceTag(ttidConman, "Unadvise %d", dwCookie);
  1648. hr = IConnectionPointImpl<CConnectionManager, &IID_INetConnectionNotifySink>::Unadvise(dwCookie);
  1649. Lock();
  1650. BOOL fFound = FALSE;
  1651. for (ITERUSERNOTIFYMAP iter = m_mapNotify.begin(); iter != m_mapNotify.end(); iter++)
  1652. {
  1653. if (iter->second->dwCookie == dwCookie)
  1654. {
  1655. fFound = TRUE;
  1656. delete iter->second;
  1657. m_mapNotify.erase(iter);
  1658. break;
  1659. }
  1660. }
  1661. Unlock();
  1662. if (!fFound)
  1663. {
  1664. TraceTag(ttidError, "Unadvise cannot find advise for cookie 0x%08x in notify map", dwCookie);
  1665. }
  1666. #ifdef DBG
  1667. LPWSTR* ppszAdviseUsers;
  1668. DWORD dwCount;
  1669. HRESULT hrT = GetClientAdvises(&ppszAdviseUsers, &dwCount);
  1670. if (SUCCEEDED(hrT))
  1671. {
  1672. if (!dwCount)
  1673. {
  1674. TraceTag(ttidConman, "Unadvise removed the last advise client");
  1675. }
  1676. else
  1677. {
  1678. TraceTag(ttidConman, "Advise client list after ::Unadvise:");
  1679. }
  1680. for (DWORD x = 0; x < dwCount; x++)
  1681. {
  1682. LPWSTR szUserName = ppszAdviseUsers[x];
  1683. TraceTag(ttidConman, "%x: %S", x, szUserName);
  1684. }
  1685. CoTaskMemFree(ppszAdviseUsers);
  1686. }
  1687. #endif
  1688. return hr;
  1689. }
  1690. #if DBG
  1691. //+---------------------------------------------------------------------------
  1692. // INetConnectionManagerDebug
  1693. //
  1694. DWORD
  1695. WINAPI
  1696. ConmanNotifyTest (
  1697. PVOID pvContext
  1698. )
  1699. {
  1700. TraceFileFunc(ttidConman);
  1701. HRESULT hr;
  1702. RASENUMENTRYDETAILS* pDetails;
  1703. DWORD cDetails;
  1704. hr = HrRasEnumAllEntriesWithDetails (NULL,
  1705. &pDetails, &cDetails);
  1706. if (SUCCEEDED(hr))
  1707. {
  1708. RASEVENT Event;
  1709. for (DWORD i = 0; i < cDetails; i++)
  1710. {
  1711. Event.Type = ENTRY_ADDED;
  1712. Event.Details = pDetails[i];
  1713. RasEventNotify (&Event);
  1714. Event.Type = ENTRY_MODIFIED;
  1715. RasEventNotify (&Event);
  1716. Event.Type = ENTRY_CONNECTED;
  1717. Event.guidId = pDetails[i].guidId;
  1718. RasEventNotify (&Event);
  1719. Event.Type = ENTRY_DISCONNECTED;
  1720. Event.guidId = pDetails[i].guidId;
  1721. RasEventNotify (&Event);
  1722. Event.Type = ENTRY_RENAMED;
  1723. lstrcpyW (Event.pszwNewName, L"foobar");
  1724. RasEventNotify (&Event);
  1725. Event.Type = ENTRY_DELETED;
  1726. Event.guidId = pDetails[i].guidId;
  1727. RasEventNotify (&Event);
  1728. }
  1729. MemFree (pDetails);
  1730. }
  1731. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  1732. TraceErrorOptional ("ConmanNotifyTest", hr, (S_FALSE == hr));
  1733. return hr;
  1734. }
  1735. STDMETHODIMP
  1736. CConnectionManager::NotifyTestStart ()
  1737. {
  1738. TraceFileFunc(ttidConman);
  1739. HRESULT hr = S_OK;
  1740. if (!QueueUserWorkItem (ConmanNotifyTest, NULL, WT_EXECUTEDEFAULT))
  1741. {
  1742. hr = HrFromLastWin32Error ();
  1743. }
  1744. TraceErrorOptional ("CConnectionManager::NotifyTestStart", hr, (S_FALSE == hr));
  1745. return hr;
  1746. }
  1747. STDMETHODIMP
  1748. CConnectionManager::NotifyTestStop ()
  1749. {
  1750. TraceFileFunc(ttidConman);
  1751. return S_OK;
  1752. }
  1753. #endif // DBG