Source code of Windows XP (NT5)
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
18 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. connsink.c
  5. Abstract:
  6. Implements a COM sink object on which to receive connection folder
  7. events
  8. Author:
  9. CharlWi (Charlie Wickham) 11/30/98 - heavily ripped off from
  10. net\config\shell\folder\notify.cpp, originally authored by
  11. ShaunCo (Shaun Cox)
  12. Revision History:
  13. --*/
  14. #define UNICODE 1
  15. #include "connsink.h"
  16. #include <iaccess.h>
  17. extern "C" {
  18. #include "nmp.h"
  19. VOID
  20. ProcessNameChange(
  21. GUID * GuidId,
  22. LPCWSTR NewName
  23. );
  24. }
  25. EXTERN_C const CLSID CLSID_ConnectionManager;
  26. EXTERN_C const IID IID_INetConnectionNotifySink;
  27. #define INVALID_COOKIE -1
  28. CComModule _Module;
  29. DWORD AdviseCookie = INVALID_COOKIE;
  30. //static
  31. HRESULT
  32. CConnectionNotifySink::CreateInstance (
  33. REFIID riid,
  34. VOID** ppv)
  35. {
  36. HRESULT hr = E_OUTOFMEMORY;
  37. // Initialize the output parameter.
  38. //
  39. *ppv = NULL;
  40. CConnectionNotifySink* pObj;
  41. pObj = new CComObject <CConnectionNotifySink>;
  42. if (pObj)
  43. {
  44. // Do the standard CComCreator::CreateInstance stuff.
  45. //
  46. pObj->SetVoid (NULL);
  47. pObj->InternalFinalConstructAddRef ();
  48. hr = pObj->FinalConstruct ();
  49. pObj->InternalFinalConstructRelease ();
  50. if (SUCCEEDED(hr))
  51. {
  52. hr = pObj->QueryInterface (riid, ppv);
  53. }
  54. if (FAILED(hr))
  55. {
  56. delete pObj;
  57. }
  58. }
  59. if ( FAILED( hr )) {
  60. ClRtlLogPrint(LOG_CRITICAL,
  61. "[NM] Unable to create Net Connection Manager advise sink "
  62. "object, status %08X.\n",
  63. hr);
  64. }
  65. return hr;
  66. } // CConnectionNotifySink::CreateInstance
  67. //+---------------------------------------------------------------------------
  68. //
  69. // Member: CConnectionNotifySink::~CConnectionNotifySink
  70. //
  71. // Purpose: Clean up the sink object
  72. //
  73. // Arguments:
  74. // (none)
  75. //
  76. // Returns:
  77. //
  78. CConnectionNotifySink::~CConnectionNotifySink()
  79. {
  80. }
  81. //
  82. // all we really care about are renaming events hence the rest of the routines
  83. // are stubbed out
  84. //
  85. HRESULT
  86. CConnectionNotifySink::ConnectionAdded (
  87. const NETCON_PROPERTIES_EX* pPropsEx)
  88. {
  89. return E_NOTIMPL;
  90. }
  91. HRESULT
  92. CConnectionNotifySink::ConnectionBandWidthChange (
  93. const GUID* pguidId)
  94. {
  95. return E_NOTIMPL;
  96. }
  97. HRESULT
  98. CConnectionNotifySink::ConnectionDeleted (
  99. const GUID* pguidId)
  100. {
  101. return E_NOTIMPL;
  102. }
  103. HRESULT
  104. CConnectionNotifySink::ConnectionModified (
  105. const NETCON_PROPERTIES_EX* pPropsEx)
  106. {
  107. ProcessNameChange(const_cast<GUID *>(&(pPropsEx->guidId)), pPropsEx->bstrName );
  108. return S_OK;
  109. }
  110. HRESULT
  111. CConnectionNotifySink::ConnectionRenamed (
  112. const GUID* GuidId,
  113. LPCWSTR NewName)
  114. {
  115. ProcessNameChange(( GUID *)GuidId, NewName );
  116. return S_OK;
  117. } // CConnectionNotifySink::ConnectionRenamed
  118. HRESULT
  119. CConnectionNotifySink::ConnectionStatusChange (
  120. const GUID* pguidId,
  121. NETCON_STATUS Status)
  122. {
  123. return E_NOTIMPL;
  124. }
  125. HRESULT
  126. CConnectionNotifySink::RefreshAll ()
  127. {
  128. return E_NOTIMPL;
  129. }
  130. HRESULT CConnectionNotifySink::ConnectionAddressChange (
  131. const GUID* pguidId )
  132. {
  133. return E_NOTIMPL;
  134. }
  135. HRESULT CConnectionNotifySink::ShowBalloon(
  136. IN const GUID* pguidId,
  137. IN const BSTR szCookie,
  138. IN const BSTR szBalloonText)
  139. {
  140. return E_NOTIMPL;
  141. }
  142. HRESULT CConnectionNotifySink::DisableEvents(
  143. IN const BOOL fDisable,
  144. IN const ULONG ulDisableTimeout)
  145. {
  146. return E_NOTIMPL;
  147. }
  148. //+---------------------------------------------------------------------------
  149. //
  150. // Function: HrGetNotifyConPoint
  151. //
  152. // Purpose: Common code for getting the connection point for use in
  153. // NotifyAdd and NotifyRemove
  154. //
  155. // Arguments:
  156. // ppConPoint [out] Return ptr for IConnectionPoint
  157. //
  158. // Returns:
  159. //
  160. // Author: jeffspr 24 Aug 1998
  161. //
  162. // Notes:
  163. //
  164. HRESULT HrGetNotifyConPoint(
  165. IConnectionPoint ** ppConPoint)
  166. {
  167. HRESULT hr;
  168. IConnectionPointContainer * pContainer = NULL;
  169. CL_ASSERT(ppConPoint);
  170. // Get the debug interface from the connection manager
  171. //
  172. hr = CoCreateInstance(CLSID_ConnectionManager, NULL,
  173. CLSCTX_LOCAL_SERVER,
  174. IID_IConnectionPointContainer,
  175. (LPVOID*)&pContainer);
  176. if (SUCCEEDED(hr)) {
  177. IConnectionPoint * pConPoint = NULL;
  178. // Get the connection point itself and fill in the return param
  179. // on success
  180. //
  181. hr = pContainer->FindConnectionPoint(
  182. IID_INetConnectionNotifySink,
  183. &pConPoint);
  184. if (SUCCEEDED(hr)) {
  185. //
  186. // set up a proxy on the connection point interface that will
  187. // identify ourselves as ourselves.
  188. //
  189. hr = CoSetProxyBlanket(pConPoint,
  190. RPC_C_AUTHN_WINNT, // use NT default security
  191. RPC_C_AUTHZ_NONE, // use NT default authentication
  192. NULL, // must be null if default
  193. RPC_C_AUTHN_LEVEL_CALL, // call
  194. RPC_C_IMP_LEVEL_IMPERSONATE,
  195. NULL, // use process token
  196. EOAC_NONE);
  197. if (SUCCEEDED(hr)) {
  198. *ppConPoint = pConPoint;
  199. } else {
  200. ClRtlLogPrint(LOG_CRITICAL,
  201. "[NM] Couldn't set proxy blanket on Net Connection "
  202. "point, status %1!08X!.\n",
  203. hr);
  204. pConPoint->Release();
  205. }
  206. } else {
  207. ClRtlLogPrint(LOG_CRITICAL,
  208. "[NM] Couldn't find notify sink connection point on Net Connection "
  209. "Manager, status %1!08X!.\n",
  210. hr);
  211. }
  212. pContainer->Release();
  213. } else {
  214. ClRtlLogPrint(LOG_CRITICAL,
  215. "[NM] Couldn't establish connection point with Net Connection "
  216. "Manager, status %1!08X!.\n",
  217. hr);
  218. }
  219. return hr;
  220. }
  221. EXTERN_C {
  222. HRESULT
  223. NmpGrantAccessToNotifySink(
  224. VOID
  225. )
  226. /*++
  227. Routine Description:
  228. allow localsystem and cluster service account access to make callbacks
  229. into the service.
  230. stolen from private\admin\snapin\netsnap\remrras\server\remrras.cpp and
  231. code reviewed by SajiA
  232. Arguments:
  233. None
  234. Return Value:
  235. ERROR_SUCCESS if everything went ok.
  236. --*/
  237. {
  238. IAccessControl* pAccessControl = NULL;
  239. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  240. PSID pSystemSid = NULL;
  241. HANDLE processToken = NULL;
  242. ULONG tokenUserSize;
  243. PTOKEN_USER processTokenUser = NULL;
  244. DWORD status;
  245. HRESULT hr = CoCreateInstance(CLSID_DCOMAccessControl,
  246. NULL,
  247. CLSCTX_INPROC_SERVER,
  248. IID_IAccessControl,
  249. (void**)&pAccessControl);
  250. if(FAILED(hr)) {
  251. goto Error;
  252. }
  253. //
  254. // Setup the property list. We use the NULL property because we are trying
  255. // to adjust the security of the object itself
  256. //
  257. ACTRL_ACCESSW access;
  258. ACTRL_PROPERTY_ENTRYW propEntry;
  259. access.cEntries = 1;
  260. access.pPropertyAccessList = &propEntry;
  261. ACTRL_ACCESS_ENTRY_LISTW entryList;
  262. propEntry.lpProperty = NULL;
  263. propEntry.pAccessEntryList = &entryList;
  264. propEntry.fListFlags = 0;
  265. //
  266. // Setup the access control list for the default property
  267. //
  268. ACTRL_ACCESS_ENTRYW entry[2];
  269. entryList.cEntries = 2;
  270. entryList.pAccessList = entry;
  271. //
  272. // Setup the access control entry for localsystem
  273. //
  274. entry[0].fAccessFlags = ACTRL_ACCESS_ALLOWED;
  275. entry[0].Access = COM_RIGHTS_EXECUTE;
  276. entry[0].ProvSpecificAccess = 0;
  277. entry[0].Inheritance = NO_INHERITANCE;
  278. entry[0].lpInheritProperty = NULL;
  279. // NT requires the system account to have access (for launching)
  280. entry[0].Trustee.pMultipleTrustee = NULL;
  281. entry[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  282. entry[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  283. entry[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
  284. //
  285. // allocate and init the SYSTEM sid
  286. //
  287. if ( !AllocateAndInitializeSid( &siaNtAuthority,
  288. 1,
  289. SECURITY_LOCAL_SYSTEM_RID,
  290. 0, 0, 0, 0, 0, 0, 0,
  291. &pSystemSid ) ) {
  292. status = GetLastError();
  293. goto Error;
  294. }
  295. entry[0].Trustee.ptstrName = (PWCHAR)pSystemSid;;
  296. //
  297. // Setup the access control entry for cluster service account
  298. //
  299. entry[1].fAccessFlags = ACTRL_ACCESS_ALLOWED;
  300. entry[1].Access = COM_RIGHTS_EXECUTE;
  301. entry[1].ProvSpecificAccess = 0;
  302. entry[1].Inheritance = NO_INHERITANCE;
  303. entry[1].lpInheritProperty = NULL;
  304. entry[1].Trustee.pMultipleTrustee = NULL;
  305. entry[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  306. entry[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  307. entry[1].Trustee.TrusteeType = TRUSTEE_IS_USER;
  308. status = NtOpenProcessToken(
  309. NtCurrentProcess(),
  310. TOKEN_QUERY,
  311. &processToken
  312. );
  313. if (!NT_SUCCESS(status)) {
  314. goto Error;
  315. }
  316. //
  317. // find out the size of token, allocate and requery to get info
  318. //
  319. status = NtQueryInformationToken(
  320. processToken,
  321. TokenUser,
  322. NULL,
  323. 0,
  324. &tokenUserSize
  325. );
  326. CL_ASSERT( status == STATUS_BUFFER_TOO_SMALL );
  327. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  328. goto Error;
  329. }
  330. processTokenUser = (PTOKEN_USER) LocalAlloc( 0, tokenUserSize );
  331. if (( processToken == NULL ) || ( processTokenUser == NULL )) {
  332. status = STATUS_INSUFFICIENT_RESOURCES;
  333. goto Error;
  334. }
  335. status = NtQueryInformationToken(
  336. processToken,
  337. TokenUser,
  338. processTokenUser,
  339. tokenUserSize,
  340. &tokenUserSize
  341. );
  342. if (!NT_SUCCESS(status)) {
  343. goto Error;
  344. }
  345. entry[1].Trustee.ptstrName = (PWCHAR)processTokenUser->User.Sid;
  346. //
  347. // grant access to this mess
  348. //
  349. hr = pAccessControl->GrantAccessRights(&access);
  350. if( SUCCEEDED(hr))
  351. {
  352. hr = CoInitializeSecurity(pAccessControl,
  353. -1,
  354. NULL,
  355. NULL,
  356. RPC_C_AUTHN_LEVEL_CONNECT,
  357. RPC_C_IMP_LEVEL_IDENTIFY,
  358. NULL,
  359. EOAC_ACCESS_CONTROL,
  360. NULL);
  361. }
  362. Error:
  363. if(pAccessControl) {
  364. pAccessControl->Release();
  365. }
  366. if (processTokenUser != NULL) {
  367. LocalFree( processTokenUser );
  368. }
  369. if (processToken != NULL) {
  370. NtClose(processToken);
  371. }
  372. return hr;
  373. }
  374. HRESULT
  375. NmpInitializeConnectoidAdviseSink(
  376. VOID
  377. )
  378. /*++
  379. Routine Description:
  380. Get an instance pointer to the conn mgr's connection point object and hook
  381. up our advice sink so we can catch connectoid rename events
  382. Arguments:
  383. None
  384. Return Value:
  385. ERROR_SUCCESS if everything worked...
  386. --*/
  387. {
  388. HRESULT hr = S_OK; // Not returned, but used for debugging
  389. IConnectionPoint * pConPoint = NULL;
  390. INetConnectionNotifySink * pSink = NULL;
  391. PSECURITY_DESCRIPTOR sinkSD;
  392. hr = NmpGrantAccessToNotifySink();
  393. if ( SUCCEEDED( hr )) {
  394. hr = HrGetNotifyConPoint(&pConPoint);
  395. if (SUCCEEDED(hr)) {
  396. // Create the notify sink
  397. //
  398. hr = CConnectionNotifySink::CreateInstance(
  399. IID_INetConnectionNotifySink,
  400. (LPVOID*)&pSink);
  401. if (SUCCEEDED(hr)) {
  402. CL_ASSERT(pSink);
  403. hr = pConPoint->Advise(pSink, &AdviseCookie);
  404. if ( !SUCCEEDED( hr )) {
  405. ClRtlLogPrint(LOG_UNUSUAL,
  406. "[NM] Couldn't initialize Net Connection Manager advise "
  407. "sink, status %1!08X!\n",
  408. hr);
  409. }
  410. pSink->Release();
  411. } else {
  412. hr = GetLastError();
  413. ClRtlLogPrint(LOG_UNUSUAL,
  414. "[NM] Couldn't create sink instance, status %1!08X!\n",
  415. hr);
  416. }
  417. pConPoint->Release();
  418. }
  419. } else {
  420. ClRtlLogPrint(LOG_UNUSUAL,
  421. "[NM] CoInitializeSecurity failed, status %1!08X!\n",
  422. hr);
  423. }
  424. if ( FAILED( hr )) {
  425. ClRtlLogPrint(LOG_UNUSUAL,
  426. "[NM] Couldn't initialize Net Connection Manager advise "
  427. "sink, status %1!08X!\n",
  428. hr);
  429. AdviseCookie = INVALID_COOKIE;
  430. }
  431. return hr;
  432. } // NmpInitializeConnectoidAdviseSink
  433. VOID
  434. NmCloseConnectoidAdviseSink(
  435. VOID
  436. )
  437. /*++
  438. Routine Description:
  439. close down the conn mgr event sink. this routine is public since it is
  440. called prior to CoUninitialize in ClusterShutdown()
  441. Arguments:
  442. None
  443. Return Value:
  444. None
  445. --*/
  446. {
  447. HRESULT hr = S_OK;
  448. IConnectionPoint * pConPoint = NULL;
  449. if ( AdviseCookie != INVALID_COOKIE ) {
  450. hr = HrGetNotifyConPoint(&pConPoint);
  451. if (SUCCEEDED(hr)) {
  452. // Unadvise
  453. //
  454. hr = pConPoint->Unadvise(AdviseCookie);
  455. AdviseCookie = INVALID_COOKIE;
  456. pConPoint->Release();
  457. }
  458. if ( FAILED( hr )) {
  459. ClRtlLogPrint(LOG_UNUSUAL,
  460. "[NM] Couldn't close Net Connection Manager advise sink, status %1!08X!\n",
  461. hr);
  462. }
  463. }
  464. } // NmCloseConnectoidAdviseSink
  465. VOID
  466. ProcessNameChange(
  467. GUID * GuidId,
  468. LPCWSTR NewName
  469. )
  470. /*++
  471. Routine Description:
  472. wrapper that enums the net interfaces
  473. Arguments:
  474. GuidId - pointer to connectoid that changed
  475. NewName - pointer to new name of connectoid
  476. Return Value:
  477. None
  478. --*/
  479. {
  480. RPC_STATUS rpcStatus;
  481. LPWSTR connectoidId = NULL;
  482. CL_ASSERT(GuidId);
  483. CL_ASSERT(NewName);
  484. rpcStatus = UuidToString( (GUID *) GuidId, &connectoidId);
  485. if ( rpcStatus == RPC_S_OK ) {
  486. PNM_INTERFACE netInterface;
  487. DWORD status;
  488. PLIST_ENTRY entry;
  489. ClRtlLogPrint(LOG_NOISE,
  490. "[NM] Received notification that name for connectoid %1!ws! was changed "
  491. "to '%2!ws!'\n",
  492. connectoidId,
  493. NewName);
  494. NmpAcquireLock();
  495. //
  496. // enum the interfaces, looking for the connectoid GUID as the
  497. // adapter ID
  498. //
  499. for (entry = NmpInterfaceList.Flink;
  500. entry != &NmpInterfaceList;
  501. entry = entry->Flink
  502. )
  503. {
  504. netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, Linkage);
  505. if ( lstrcmpiW( connectoidId , netInterface->AdapterId ) == 0 ) {
  506. PNM_NETWORK network = netInterface->Network;
  507. LPWSTR networkName = (LPWSTR) OmObjectName( network );
  508. if ( lstrcmpW( networkName, NewName ) != 0 ) {
  509. NM_NETWORK_INFO netInfo;
  510. //
  511. // For some reason, OmReferenceObject causes a compiler
  512. // error here. Likely a header ordering problem. The
  513. // function has been wrappered as a workaround.
  514. //
  515. NmpReferenceNetwork(network);
  516. NmpReleaseLock();
  517. netInfo.Id = (LPWSTR) OmObjectId( network );
  518. netInfo.Name = (LPWSTR) NewName;
  519. status = NmpSetNetworkName( &netInfo );
  520. if ( status != ERROR_SUCCESS ) {
  521. ClRtlLogPrint( LOG_UNUSUAL,
  522. "[NM] Couldn't rename network '%1!ws!' to '%2!ws!', status %3!u!\n",
  523. networkName,
  524. NewName,
  525. status
  526. );
  527. //If the error condition is due to the object
  528. //already existing revert back to the old name.
  529. if(status == ERROR_OBJECT_ALREADY_EXISTS) {
  530. DWORD tempStatus = ERROR_SUCCESS;
  531. INetConnection *connectoid;
  532. ClRtlLogPrint(LOG_UNUSUAL,
  533. "[NM] Reverting back network name to '%1!ws!', from '%2!ws!\n",
  534. networkName,
  535. NewName
  536. );
  537. connectoid = ClRtlFindConnectoidByGuid(connectoidId);
  538. if(connectoid != NULL){
  539. tempStatus = ClRtlSetConnectoidName(
  540. connectoid,
  541. networkName);
  542. }
  543. if((tempStatus != ERROR_SUCCESS) ||
  544. (connectoid == NULL)) {
  545. ClRtlLogPrint(LOG_UNUSUAL,
  546. "[NM] Failed to set name of network connection"
  547. "%1!ws!, status %2!u!\n",
  548. networkName,
  549. tempStatus);
  550. }
  551. }
  552. }
  553. NmpDereferenceNetwork(network);
  554. }
  555. else {
  556. NmpReleaseLock();
  557. }
  558. break;
  559. }
  560. }
  561. if ( entry == &NmpInterfaceList ) {
  562. NmpReleaseLock();
  563. ClRtlLogPrint(LOG_UNUSUAL,
  564. "[NM] Couldn't find net interface for connectoid '%1!ws!'\n",
  565. connectoidId
  566. );
  567. }
  568. RpcStringFree( &connectoidId );
  569. }
  570. return;
  571. } // ProcessNameChange
  572. } // EXTERN_C