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.

1175 lines
34 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: aqrpcsvr.cpp
  5. //
  6. // Description: Implementation of AQ RPC server
  7. //
  8. // Author: Mike Swafford (MikeSwa)
  9. //
  10. // History:
  11. // 6/5/99 - MikeSwa Created
  12. //
  13. // Copyright (C) 1999 Microsoft Corporation
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include "aqprecmp.h"
  17. #include "aqrpcsvr.h"
  18. #include "aqadmrpc.h"
  19. #include <inetcom.h>
  20. #include <iiscnfg.h>
  21. LIST_ENTRY CAQRpcSvrInst::s_liInstancesHead;
  22. CShareLockNH CAQRpcSvrInst::s_slPrivateData;
  23. RPC_BINDING_VECTOR *CAQRpcSvrInst::s_pRpcBindingVector = NULL;
  24. BOOL CAQRpcSvrInst::s_fEndpointsRegistered = FALSE;
  25. //
  26. // Quick and dirty string validation
  27. //
  28. static inline BOOL pValidateStringPtr(LPWSTR lpwszString, DWORD dwMaxLength)
  29. {
  30. if (IsBadStringPtr((LPCTSTR)lpwszString, dwMaxLength))
  31. return(FALSE);
  32. while (dwMaxLength--)
  33. if (*lpwszString++ == 0)
  34. return(TRUE);
  35. return(FALSE);
  36. }
  37. //---[ HrInitializeAQRpc ]-----------------------------------------------------
  38. //
  39. //
  40. // Description:
  41. // Initializes AQ RPC. This should only be called once per service
  42. // startup (not VS). Caller in responable for ensuring that this and
  43. // HrInitializeAQRpc are called in a thread safe manner.
  44. // Parameters:
  45. // -
  46. // Returns:
  47. // S_OK on success
  48. // Error code from RPC
  49. // History:
  50. // 6/5/99 - MikeSwa Created
  51. //
  52. //-----------------------------------------------------------------------------
  53. HRESULT CAQRpcSvrInst::HrInitializeAQRpc()
  54. {
  55. TraceFunctEnterEx((LPARAM) NULL, "CAQRpcSvrInst::HrInitializeAQRpc");
  56. HRESULT hr = S_OK;
  57. RPC_STATUS status = RPC_S_OK;
  58. InitializeListHead(&s_liInstancesHead);
  59. s_pRpcBindingVector = NULL;
  60. s_fEndpointsRegistered = FALSE;
  61. //Listen on the appropriate protocols sequences
  62. status = RpcServerUseAllProtseqs(RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  63. NULL);
  64. if (status != RPC_S_OK)
  65. goto Exit;
  66. //Advertise the appropriate interface
  67. status = RpcServerRegisterIfEx(IAQAdminRPC_v1_0_s_ifspec, NULL, NULL,
  68. RPC_IF_AUTOLISTEN,
  69. RPC_C_PROTSEQ_MAX_REQS_DEFAULT, NULL);
  70. if (status != RPC_S_OK)
  71. goto Exit;
  72. //Get the dynamic endpoints
  73. status = RpcServerInqBindings(&s_pRpcBindingVector);
  74. if (status != RPC_S_OK)
  75. goto Exit;
  76. //Register the endpoints
  77. status = RpcEpRegister(IAQAdminRPC_v1_0_s_ifspec, s_pRpcBindingVector,
  78. NULL, NULL);
  79. if (status != RPC_S_OK)
  80. goto Exit;
  81. s_fEndpointsRegistered = TRUE;
  82. Exit:
  83. if (status != RPC_S_OK)
  84. hr = HRESULT_FROM_WIN32(status);
  85. TraceFunctLeave();
  86. return hr;
  87. }
  88. //---[ HrDeinitializeAQRpc ]----------------------------------------------------
  89. //
  90. //
  91. // Description:
  92. // Do global RPC cleanup
  93. // Parameters:
  94. // -
  95. // Returns:
  96. // S_OK on success
  97. // Error code from RPC otherwise
  98. // History:
  99. // 6/5/99 - MikeSwa Created
  100. //
  101. //-----------------------------------------------------------------------------
  102. HRESULT CAQRpcSvrInst::HrDeinitializeAQRpc()
  103. {
  104. TraceFunctEnterEx((LPARAM) NULL, "CAQRpcSvrInst::HrDeinitializeAQRpc");
  105. HRESULT hr = S_OK;
  106. RPC_STATUS status = RPC_S_OK;
  107. if (s_fEndpointsRegistered) {
  108. status = RpcEpUnregister(IAQAdminRPC_v1_0_s_ifspec, s_pRpcBindingVector, NULL);
  109. if (status != RPC_S_OK) hr = HRESULT_FROM_WIN32(status);
  110. }
  111. if (s_pRpcBindingVector) {
  112. status = RpcBindingVectorFree(&s_pRpcBindingVector);
  113. if (status != RPC_S_OK) hr = HRESULT_FROM_WIN32(status);
  114. }
  115. status = RpcServerUnregisterIf(IAQAdminRPC_v1_0_s_ifspec, NULL, 0);
  116. if (status != RPC_S_OK) hr = HRESULT_FROM_WIN32(status);
  117. s_fEndpointsRegistered = FALSE;
  118. s_pRpcBindingVector = NULL;
  119. TraceFunctLeave();
  120. return hr;
  121. }
  122. //---[ HrInitializeAQServerInstanceRPC ]---------------------------------------
  123. //
  124. //
  125. // Description:
  126. // Add instance to RPC interface
  127. // Parameters:
  128. // IN paqinst Instnace to add to interface
  129. // IN dwVirtualServerID Virtual server ID of instance
  130. // Returns:
  131. // S_OK on success
  132. // History:
  133. // 6/5/99 - MikeSwa Created
  134. //
  135. //-----------------------------------------------------------------------------
  136. HRESULT CAQRpcSvrInst::HrInitializeAQServerInstanceRPC(CAQSvrInst *paqinst,
  137. DWORD dwVirtualServerID,
  138. ISMTPServer *pISMTPServer)
  139. {
  140. TraceFunctEnterEx((LPARAM) paqinst,
  141. "CAQRpcSvrInst::HrInitializeAQServerInstanceRPC");
  142. HRESULT hr = S_OK;
  143. CAQRpcSvrInst *paqrpc = NULL;
  144. paqrpc = CAQRpcSvrInst::paqrpcGetRpcSvrInstance(dwVirtualServerID);
  145. if (paqrpc)
  146. {
  147. _ASSERT(0 && "Instance already added to RPC interface");
  148. paqrpc->Release();
  149. paqrpc = NULL;
  150. goto Exit;
  151. }
  152. paqrpc = new CAQRpcSvrInst(paqinst, dwVirtualServerID, pISMTPServer);
  153. if (!paqrpc)
  154. {
  155. hr = E_OUTOFMEMORY;
  156. goto Exit;
  157. }
  158. Exit:
  159. TraceFunctLeave();
  160. return hr;
  161. }
  162. //---[ HrDeinitializeAQServerInstanceRPC ]-------------------------------------
  163. //
  164. //
  165. // Description:
  166. // Remove instance from RPC interface
  167. // Parameters:
  168. // IN paqinst Instnace to remove from interface
  169. // IN dwVirtualServerID Virtual server ID of instance
  170. // Returns:
  171. // S_OK on success
  172. // History:
  173. // 6/5/99 - MikeSwa Created
  174. //
  175. //-----------------------------------------------------------------------------
  176. HRESULT CAQRpcSvrInst::HrDeinitializeAQServerInstanceRPC(CAQSvrInst *paqinst,
  177. DWORD dwVirtualServerID)
  178. {
  179. TraceFunctEnterEx((LPARAM) paqinst,
  180. "CAQRpcSvrInst::HrDeinitializeAQServerInstanceRPC");
  181. HRESULT hr = S_OK;
  182. CAQRpcSvrInst *paqrpc = NULL;
  183. paqrpc = CAQRpcSvrInst::paqrpcGetRpcSvrInstance(dwVirtualServerID);
  184. if (!paqrpc)
  185. goto Exit; //allow calls if HrInitializeAQServerInstanceRPC failed
  186. //Found it
  187. //$$TODO - verify the paqinst is correct
  188. paqrpc->SignalShutdown();
  189. //Remove from list of entries
  190. s_slPrivateData.ExclusiveLock();
  191. RemoveEntryList(&(paqrpc->m_liInstances));
  192. s_slPrivateData.ExclusiveUnlock();
  193. paqrpc->Release(); //release reference associated with list
  194. Exit:
  195. if (paqrpc)
  196. paqrpc->Release();
  197. TraceFunctLeave();
  198. return hr;
  199. }
  200. //---[ CAQRpcSvrInst::CAQRpcSvrInst ]------------------------------------------
  201. //
  202. //
  203. // Description:
  204. // Constructor for CAQRpcSvrInst class
  205. // Parameters:
  206. // IN paqinst Instnace to remove from interface
  207. // IN dwVirtualServerID Virtual server ID of instance
  208. // Returns:
  209. // -
  210. // History:
  211. // 6/6/99 - MikeSwa Created
  212. //
  213. //-----------------------------------------------------------------------------
  214. CAQRpcSvrInst::CAQRpcSvrInst(CAQSvrInst *paqinst, DWORD dwVirtualServerID,
  215. ISMTPServer *pISMTPServer)
  216. {
  217. _ASSERT(paqinst);
  218. _ASSERT(pISMTPServer);
  219. m_paqinst = paqinst;
  220. m_dwVirtualServerID = dwVirtualServerID;
  221. m_pISMTPServer = pISMTPServer;
  222. m_dwSignature = CAQRpcSvrInst_Sig;
  223. if (m_paqinst)
  224. m_paqinst->AddRef();
  225. if (m_pISMTPServer)
  226. m_pISMTPServer->AddRef();
  227. //Add to list of virtual server instaces
  228. s_slPrivateData.ExclusiveLock();
  229. InsertHeadList(&s_liInstancesHead, &m_liInstances);
  230. s_slPrivateData.ExclusiveUnlock();
  231. }
  232. //---[ CAQRpcSvrInst::~CAQRpcSvrInst ]-----------------------------------------
  233. //
  234. //
  235. // Description:
  236. // Desctructor for CAQRpcSvrInst
  237. // Parameters:
  238. // -
  239. // Returns:
  240. // -
  241. // History:
  242. // 6/6/99 - MikeSwa Created
  243. //
  244. //-----------------------------------------------------------------------------
  245. CAQRpcSvrInst::~CAQRpcSvrInst()
  246. {
  247. if (m_paqinst)
  248. m_paqinst->Release();
  249. if (m_pISMTPServer)
  250. m_pISMTPServer->Release();
  251. m_dwSignature = CAQRpcSvrInst_SigFree;
  252. }
  253. //---[ CAQRpcSvrInst::paqrpcGetRpcSvrInstance ]--------------------------------
  254. //
  255. //
  256. // Description:
  257. // Gets the CAQRpcSvrInst for a given virtual server ID
  258. // Parameters:
  259. // IN dwVirtualServerID Virtual server ID of instance
  260. // Returns:
  261. // Pointer to appropriate CAQRpcSvrInst on success
  262. // NULL if not found
  263. // History:
  264. // 6/6/99 - MikeSwa Created
  265. //
  266. //-----------------------------------------------------------------------------
  267. CAQRpcSvrInst *CAQRpcSvrInst::paqrpcGetRpcSvrInstance(DWORD dwVirtualServerID)
  268. {
  269. LIST_ENTRY *pli = NULL;
  270. CAQRpcSvrInst *paqrpc = NULL;
  271. s_slPrivateData.ShareLock();
  272. pli = s_liInstancesHead.Flink;
  273. while (pli && (pli != &s_liInstancesHead))
  274. {
  275. paqrpc = CONTAINING_RECORD(pli, CAQRpcSvrInst, m_liInstances);
  276. //$$TODO check signature
  277. if (paqrpc->m_dwVirtualServerID == dwVirtualServerID)
  278. {
  279. paqrpc->AddRef();
  280. break; //found it
  281. }
  282. paqrpc = NULL;
  283. pli = pli->Flink;
  284. }
  285. s_slPrivateData.ShareUnlock();
  286. return paqrpc;
  287. }
  288. //---[ CAQRpcSvrInst::fAccessCheck ]-------------------------------------------
  289. //
  290. //
  291. // Description:
  292. // Performs acess check for RPC interfaces
  293. // Parameters:
  294. // IN fWriteAccessRequired TRUE if write access is required
  295. // Returns:
  296. // TRUE if access check is succeeds
  297. // FALSE if user does not have access
  298. // History:
  299. // 6/7/99 - MikeSwa Created (from SMTP AQAdmin access code)
  300. //
  301. //-----------------------------------------------------------------------------
  302. BOOL CAQRpcSvrInst::fAccessCheck(BOOL fWriteAccessRequired)
  303. {
  304. TraceFunctEnterEx((LPARAM) this, "CAQRpcSvrInst::fAccessCheck");
  305. SECURITY_DESCRIPTOR *pSecurityDescriptor = NULL;
  306. DWORD cbSecurityDescriptor = 0;
  307. HRESULT hr = S_OK;
  308. DWORD err = ERROR_SUCCESS;
  309. BOOL fAccessAllowed = FALSE;
  310. HANDLE hAccessToken = NULL;
  311. BYTE PrivSet[200];
  312. DWORD cbPrivSet = sizeof(PrivSet);
  313. ACCESS_MASK maskAccessGranted;
  314. GENERIC_MAPPING gmGenericMapping = {
  315. MD_ACR_READ,
  316. MD_ACR_WRITE,
  317. MD_ACR_READ,
  318. MD_ACR_READ | MD_ACR_WRITE
  319. };
  320. if (!m_pISMTPServer)
  321. goto Exit; //if we cannot check it... assume if fails
  322. hr = m_pISMTPServer->ReadMetabaseData(MD_ADMIN_ACL, NULL,
  323. &cbSecurityDescriptor);
  324. if (SUCCEEDED(hr))
  325. {
  326. //We passed in NULL.. should have failed
  327. _ASSERT(0 && "Invalid response for ReadMetabaseData");
  328. goto Exit;
  329. }
  330. if ((HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr) ||
  331. !cbSecurityDescriptor)
  332. {
  333. //Can't get ACL... bail
  334. goto Exit;
  335. }
  336. pSecurityDescriptor = (SECURITY_DESCRIPTOR *) pvMalloc(cbSecurityDescriptor);
  337. if (!pSecurityDescriptor)
  338. goto Exit;
  339. hr = m_pISMTPServer->ReadMetabaseData(MD_ADMIN_ACL, (BYTE *) pSecurityDescriptor,
  340. &cbSecurityDescriptor);
  341. if (FAILED(hr))
  342. {
  343. ErrorTrace((LPARAM) this,
  344. "Error calling ReadMetabaseData for AccessCheck - hr 0x%08X", hr);
  345. goto Exit;
  346. }
  347. // Verify that we got a proper SD. if not then fail
  348. if (!IsValidSecurityDescriptor(pSecurityDescriptor))
  349. {
  350. ErrorTrace(0, "IsValidSecurityDescriptor failed with %lu", GetLastError());
  351. goto Exit;
  352. }
  353. err = RpcImpersonateClient(NULL);
  354. if (err != ERROR_SUCCESS)
  355. {
  356. ErrorTrace((LPARAM) this, "RpcImpersonateClient failed with %lu", err);
  357. goto Exit;
  358. }
  359. if (!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hAccessToken))
  360. {
  361. ErrorTrace((LPARAM) this,
  362. "OpenThreadToken Failed with %lu", GetLastError());
  363. goto Exit;
  364. }
  365. //Check access
  366. if (!AccessCheck(pSecurityDescriptor,
  367. hAccessToken,
  368. fWriteAccessRequired ? MD_ACR_WRITE : MD_ACR_READ,
  369. &gmGenericMapping,
  370. (PRIVILEGE_SET *)PrivSet,
  371. &cbPrivSet,
  372. &maskAccessGranted,
  373. &fAccessAllowed))
  374. {
  375. fAccessAllowed = FALSE;
  376. ErrorTrace((LPARAM) this,
  377. "AccessCheck Failed with %lu", GetLastError());
  378. goto Exit;
  379. }
  380. if (!fAccessAllowed)
  381. DebugTrace((LPARAM) this, "Access denied for Queue Admin RPC");
  382. //Do any additional read-only processing
  383. if (fWriteAccessRequired && fAccessAllowed &&
  384. !(MD_ACR_WRITE & maskAccessGranted))
  385. {
  386. DebugTrace((LPARAM) this, "Write Access denied for Queue Admin RPC");
  387. fAccessAllowed = FALSE;
  388. }
  389. Exit:
  390. if (pSecurityDescriptor)
  391. FreePv(pSecurityDescriptor);
  392. if (hAccessToken)
  393. CloseHandle(hAccessToken);
  394. TraceFunctLeave();
  395. return fAccessAllowed;
  396. }
  397. //---[ HrGetAQInstance ]-------------------------------------------------------
  398. //
  399. //
  400. // Description:
  401. // This is used by all of the AQ RPC's to get a pointer to AQ based on an
  402. // instance name.
  403. //
  404. // THE SHUTDOWN LOCK ON ppaqrpc IS HELD AFTER THIS CALL COMPLETES.
  405. // THE CALLER MUST CALL paqrpc->ShutdownUnlock() WHEN THEY HAVE
  406. // FINISHED THEIR QUEUE ADMIN OPERATION.
  407. // Parameters:
  408. // IN wszInstance A number containing the instance to lookup.
  409. // IN fWriteAccessRequired TRUE if write access is required
  410. // OUT ppIAdvQueueAdmin Pointer to AQ admin interface
  411. // OUT ppaqrpc Pointer to CAQRpcSvrInst
  412. // Returns:
  413. // S_OK on success
  414. // HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) if user does not have access
  415. // HRESULT_FROM_WIN32(ERROR_NOT_FOUND) if virtual server is not found
  416. // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) if server is shutting
  417. // down.
  418. // E_POINTER if pointer arguments are NULL
  419. // E_INVALIDARG if wszInstance is a bad pointer
  420. // History:
  421. // 6/11/99 - MikeSwa Created
  422. //
  423. //-----------------------------------------------------------------------------
  424. HRESULT HrGetAQInstance(IN LPWSTR wszInstance,
  425. IN BOOL fWriteAccessRequired,
  426. OUT IAdvQueueAdmin **ppIAdvQueueAdmin,
  427. OUT CAQRpcSvrInst **ppaqrpc) {
  428. TraceFunctEnter("GetAQInstance");
  429. CAQSvrInst *paqinst = NULL;
  430. IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
  431. CAQRpcSvrInst *paqrpc = NULL;
  432. BOOL fHasAccess = FALSE;
  433. DWORD dwInstance = 1;
  434. BOOL fShutdownLock = FALSE;
  435. HRESULT hr = S_OK;
  436. _ASSERT(ppIAdvQueueAdmin);
  437. _ASSERT(ppaqrpc);
  438. if (!wszInstance || !ppIAdvQueueAdmin || !ppaqrpc)
  439. {
  440. hr = E_POINTER;
  441. goto Exit;
  442. }
  443. *ppIAdvQueueAdmin = NULL;
  444. *ppaqrpc = NULL;
  445. if (!pValidateStringPtr(wszInstance, MAX_PATH))
  446. {
  447. ErrorTrace(NULL, "Invalid parameter: wszInstance\n");
  448. hr = E_INVALIDARG;
  449. goto Exit;
  450. }
  451. dwInstance = _wtoi(wszInstance);
  452. DebugTrace((LPARAM) NULL, "instance is %S (%i)", wszInstance, dwInstance);
  453. paqrpc = CAQRpcSvrInst::paqrpcGetRpcSvrInstance(dwInstance);
  454. if (!paqrpc)
  455. {
  456. ErrorTrace((LPARAM) NULL,
  457. "Error unable to find requested virtual server for QAPI %d", dwInstance);
  458. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  459. goto Exit;
  460. }
  461. //
  462. // Check for proper access.
  463. //
  464. // This should be done BEFORE the shutdown lock is grabbed because it
  465. // may require hitting the metabase (which could cause a shutdown deadlock)
  466. if (!paqrpc->fAccessCheck(fWriteAccessRequired))
  467. {
  468. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  469. goto Exit;
  470. }
  471. // Ensure that shutdown does not happen in the middle of our operation
  472. if (!paqrpc->fTryShutdownLock())
  473. {
  474. hr = HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE);
  475. goto Exit;
  476. }
  477. fShutdownLock = TRUE;
  478. paqinst = paqrpc->paqinstGetAQ();
  479. hr = paqinst->QueryInterface(IID_IAdvQueueAdmin,
  480. (void **) &pIAdvQueueAdmin);
  481. if (FAILED(hr))
  482. {
  483. pIAdvQueueAdmin = NULL;
  484. goto Exit;
  485. }
  486. Exit:
  487. if (FAILED(hr))
  488. {
  489. //cleanup
  490. if (paqrpc)
  491. {
  492. if (fShutdownLock)
  493. paqrpc->ShutdownUnlock();
  494. paqrpc->Release();
  495. }
  496. if (pIAdvQueueAdmin)
  497. pIAdvQueueAdmin->Release();
  498. pIAdvQueueAdmin = NULL;
  499. }
  500. else //return OUT params
  501. {
  502. *ppIAdvQueueAdmin = pIAdvQueueAdmin;
  503. *ppaqrpc = paqrpc;
  504. _ASSERT(ppaqrpc);
  505. _ASSERT(pIAdvQueueAdmin);
  506. }
  507. TraceFunctLeave();
  508. return hr;
  509. }
  510. NET_API_STATUS
  511. NET_API_FUNCTION
  512. AQApplyActionToLinks(
  513. AQUEUE_HANDLE wszServer,
  514. LPWSTR wszInstance,
  515. LINK_ACTION laAction)
  516. {
  517. TraceFunctEnter("AQApplyActionToLinks");
  518. HRESULT hr = S_OK;
  519. IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
  520. CAQRpcSvrInst *paqrpc = NULL;
  521. BOOL fNeedWriteAccess = TRUE;
  522. if (LA_INTERNAL == laAction) //just checking the state
  523. fNeedWriteAccess = FALSE;
  524. hr = HrGetAQInstance(wszInstance, fNeedWriteAccess, &pIAdvQueueAdmin, &paqrpc);
  525. if (FAILED(hr))
  526. return hr;
  527. hr = pIAdvQueueAdmin->ApplyActionToLinks(laAction);
  528. paqrpc->ShutdownUnlock();
  529. paqrpc->Release();
  530. pIAdvQueueAdmin->Release();
  531. TraceFunctLeave();
  532. return hr;
  533. }
  534. NET_API_STATUS
  535. NET_API_FUNCTION
  536. AQApplyActionToMessages(
  537. AQUEUE_HANDLE wszServer,
  538. LPWSTR wszInstance,
  539. QUEUELINK_ID *pqlQueueLinkId,
  540. MESSAGE_FILTER *pmfMessageFilter,
  541. MESSAGE_ACTION maMessageAction,
  542. DWORD *pcMsgs)
  543. {
  544. TraceFunctEnter("AQApplyActionToMessages");
  545. CAQRpcSvrInst *paqrpc = NULL;
  546. HRESULT hr = S_OK;
  547. IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
  548. if (IsBadReadPtr((LPVOID)pqlQueueLinkId, sizeof(QUEUELINK_ID)))
  549. {
  550. ErrorTrace(NULL, "Invalid parameter: pqlQueueLinkId\n");
  551. TraceFunctLeave();
  552. return(E_INVALIDARG);
  553. }
  554. if (IsBadReadPtr((LPVOID)pmfMessageFilter, sizeof(MESSAGE_FILTER)))
  555. {
  556. ErrorTrace(NULL, "Invalid parameter: pmfMessageFilter\n");
  557. TraceFunctLeave();
  558. return(E_INVALIDARG);
  559. }
  560. hr = HrGetAQInstance(wszInstance, TRUE, &pIAdvQueueAdmin, &paqrpc);
  561. if (SUCCEEDED(hr))
  562. {
  563. hr = pIAdvQueueAdmin->ApplyActionToMessages(pqlQueueLinkId,
  564. pmfMessageFilter,
  565. maMessageAction,
  566. pcMsgs);
  567. paqrpc->ShutdownUnlock();
  568. pIAdvQueueAdmin->Release();
  569. paqrpc->Release();
  570. }
  571. TraceFunctLeave();
  572. return hr;
  573. }
  574. NET_API_STATUS
  575. NET_API_FUNCTION
  576. AQGetQueueInfo(
  577. AQUEUE_HANDLE wszServer,
  578. LPWSTR wszInstance,
  579. QUEUELINK_ID *pqlQueueId,
  580. QUEUE_INFO *pqiQueueInfo)
  581. {
  582. TraceFunctEnter("AQGetQueueInfo");
  583. CAQRpcSvrInst *paqrpc = NULL;
  584. HRESULT hr = S_OK;
  585. IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
  586. if (IsBadReadPtr((LPVOID)pqlQueueId, sizeof(QUEUELINK_ID)))
  587. {
  588. ErrorTrace(NULL, "Invalid parameter: pqlQueueId\n");
  589. TraceFunctLeave();
  590. return(E_INVALIDARG);
  591. }
  592. if (IsBadReadPtr((LPVOID)pqiQueueInfo, sizeof(QUEUE_INFO)))
  593. {
  594. ErrorTrace(NULL, "Invalid parameter: pqiQueueInfo\n");
  595. TraceFunctLeave();
  596. return(E_INVALIDARG);
  597. }
  598. hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc);
  599. if (SUCCEEDED(hr))
  600. {
  601. hr = pIAdvQueueAdmin->GetQueueInfo(pqlQueueId,
  602. pqiQueueInfo);
  603. paqrpc->ShutdownUnlock();
  604. pIAdvQueueAdmin->Release();
  605. paqrpc->Release();
  606. }
  607. TraceFunctLeave();
  608. return hr;
  609. }
  610. NET_API_STATUS
  611. NET_API_FUNCTION
  612. AQGetLinkInfo(
  613. AQUEUE_HANDLE wszServer,
  614. LPWSTR wszInstance,
  615. QUEUELINK_ID *pqlLinkId,
  616. LINK_INFO *pliLinkInfo,
  617. HRESULT *phrLinkDiagnostic)
  618. {
  619. TraceFunctEnter("AQGetLinkInfo");
  620. CAQRpcSvrInst *paqrpc = NULL;
  621. HRESULT hr = S_OK;
  622. IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
  623. if (IsBadReadPtr((LPVOID)pqlLinkId, sizeof(QUEUELINK_ID)))
  624. {
  625. ErrorTrace(NULL, "Invalid parameter: pqlLinkId\n");
  626. TraceFunctLeave();
  627. return(E_INVALIDARG);
  628. }
  629. if (IsBadReadPtr((LPVOID)pliLinkInfo, sizeof(LINK_INFO)))
  630. {
  631. ErrorTrace(NULL, "Invalid parameter: pliLinkInfo\n");
  632. TraceFunctLeave();
  633. return(E_INVALIDARG);
  634. }
  635. if (IsBadWritePtr((LPVOID)phrLinkDiagnostic, sizeof(HRESULT)))
  636. {
  637. ErrorTrace(NULL, "Invalid parameter: pliLinkInfo\n");
  638. TraceFunctLeave();
  639. return(E_INVALIDARG);
  640. }
  641. hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc);
  642. if (SUCCEEDED(hr))
  643. {
  644. hr = pIAdvQueueAdmin->GetLinkInfo(pqlLinkId,
  645. pliLinkInfo, phrLinkDiagnostic);
  646. paqrpc->ShutdownUnlock();
  647. pIAdvQueueAdmin->Release();
  648. paqrpc->Release();
  649. }
  650. // X5:195608
  651. // I'm pretty sure the root of this has been fixed in fRPCCopyName but
  652. // just to be sure we are Firewalling against the problem here
  653. // and in vsaqlink.cpp
  654. if(SUCCEEDED(hr) && pliLinkInfo && !pliLinkInfo->szLinkName)
  655. {
  656. // ASSERT this so we can catch it internally
  657. _ASSERT(0 && "AQGetLinkInfo wants to return success with a NULL szLinkName");
  658. // return a failure because we do not have a link name - I'm going
  659. // with AQUEUE_E_INVALID_DOMAIN to prevent an admin popup
  660. hr = AQUEUE_E_INVALID_DOMAIN;
  661. }
  662. TraceFunctLeave();
  663. return hr;
  664. }
  665. NET_API_STATUS
  666. NET_API_FUNCTION
  667. AQSetLinkState(
  668. AQUEUE_HANDLE wszServer,
  669. LPWSTR wszInstance,
  670. QUEUELINK_ID *pqlLinkId,
  671. LINK_ACTION la)
  672. {
  673. TraceFunctEnter("AQSetLinkInfo");
  674. CAQRpcSvrInst *paqrpc = NULL;
  675. HRESULT hr = S_OK;
  676. IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
  677. if (IsBadReadPtr((LPVOID)pqlLinkId, sizeof(QUEUELINK_ID)))
  678. {
  679. ErrorTrace(NULL, "Invalid parameter: pqlLinkId\n");
  680. TraceFunctLeave();
  681. return(E_INVALIDARG);
  682. }
  683. hr = HrGetAQInstance(wszInstance, TRUE, &pIAdvQueueAdmin, &paqrpc);
  684. if (SUCCEEDED(hr))
  685. {
  686. hr = pIAdvQueueAdmin->SetLinkState(pqlLinkId,
  687. la);
  688. paqrpc->ShutdownUnlock();
  689. pIAdvQueueAdmin->Release();
  690. paqrpc->Release();
  691. }
  692. TraceFunctLeave();
  693. return hr;
  694. }
  695. NET_API_STATUS
  696. NET_API_FUNCTION
  697. AQGetLinkIDs(
  698. AQUEUE_HANDLE wszServer,
  699. LPWSTR wszInstance,
  700. DWORD *pcLinks,
  701. QUEUELINK_ID **prgLinks)
  702. {
  703. TraceFunctEnter("AQGetLinkIDs");
  704. CAQRpcSvrInst *paqrpc = NULL;
  705. HRESULT hr = S_OK;
  706. IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
  707. if (IsBadWritePtr((LPVOID)pcLinks, sizeof(DWORD)))
  708. {
  709. ErrorTrace(NULL, "Invalid parameter: pcLinks\n");
  710. TraceFunctLeave();
  711. return(E_INVALIDARG);
  712. }
  713. if (IsBadWritePtr((LPVOID)prgLinks, sizeof(QUEUELINK_ID *)))
  714. {
  715. ErrorTrace(NULL, "Invalid parameter: prgLinks\n");
  716. TraceFunctLeave();
  717. return(E_INVALIDARG);
  718. }
  719. hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc);
  720. if (SUCCEEDED(hr))
  721. {
  722. QUEUELINK_ID *rgLinks = NULL;
  723. DWORD cLinks = 0;
  724. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  725. // loop on calls to GetLinkIDs until we have enough memory to
  726. // get all of the links. for the first call we will always
  727. // have a NULL rgLinks and just be asking for the size. we need
  728. // to loop in case more links show up between calls
  729. while (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
  730. {
  731. hr = pIAdvQueueAdmin->GetLinkIDs(&cLinks, rgLinks);
  732. if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
  733. {
  734. if (rgLinks != NULL) MIDL_user_free(rgLinks);
  735. rgLinks = (QUEUELINK_ID *)
  736. MIDL_user_allocate(sizeof(QUEUELINK_ID) * cLinks);
  737. if (rgLinks == NULL) hr = E_OUTOFMEMORY;
  738. }
  739. }
  740. if (SUCCEEDED(hr))
  741. {
  742. *prgLinks = rgLinks;
  743. *pcLinks = cLinks;
  744. }
  745. else
  746. {
  747. *prgLinks = NULL;
  748. *pcLinks = 0;
  749. if (rgLinks) MIDL_user_free(rgLinks);
  750. }
  751. paqrpc->ShutdownUnlock();
  752. pIAdvQueueAdmin->Release();
  753. paqrpc->Release();
  754. }
  755. TraceFunctLeave();
  756. return hr;
  757. }
  758. NET_API_STATUS
  759. NET_API_FUNCTION
  760. AQGetQueueIDs(
  761. AQUEUE_HANDLE wszServer,
  762. LPWSTR wszInstance,
  763. QUEUELINK_ID *pqlLinkId,
  764. DWORD *pcQueues,
  765. QUEUELINK_ID **prgQueues)
  766. {
  767. TraceFunctEnter("AQGetQueueIDs");
  768. CAQRpcSvrInst *paqrpc = NULL;
  769. HRESULT hr = S_OK;
  770. IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
  771. if (IsBadReadPtr((LPVOID)pqlLinkId, sizeof(QUEUELINK_ID)))
  772. {
  773. ErrorTrace(NULL, "Invalid parameter: pqlLinkId\n");
  774. TraceFunctLeave();
  775. return(E_INVALIDARG);
  776. }
  777. if (IsBadWritePtr((LPVOID)pcQueues, sizeof(DWORD)))
  778. {
  779. ErrorTrace(NULL, "Invalid parameter: pcQueues\n");
  780. TraceFunctLeave();
  781. return(E_INVALIDARG);
  782. }
  783. if (IsBadWritePtr((LPVOID)prgQueues, sizeof(QUEUELINK_ID *)))
  784. {
  785. ErrorTrace(NULL, "Invalid parameter: prgQueues\n");
  786. TraceFunctLeave();
  787. return(E_INVALIDARG);
  788. }
  789. hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc);
  790. if (SUCCEEDED(hr))
  791. {
  792. QUEUELINK_ID *rgQueues = NULL;
  793. DWORD cQueues = 0;
  794. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  795. // loop on calls to GetLinkIDs until we have enough memory to
  796. // get all of the links. for the first call we will always
  797. // have a NULL rgQueues and just be asking for the size. we need
  798. // to loop in case more links show up between calls
  799. while (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
  800. {
  801. hr = pIAdvQueueAdmin->GetQueueIDs(pqlLinkId, &cQueues, rgQueues);
  802. if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
  803. {
  804. if (rgQueues != NULL) MIDL_user_free(rgQueues);
  805. rgQueues = (QUEUELINK_ID *)
  806. MIDL_user_allocate(sizeof(QUEUELINK_ID) * cQueues);
  807. if (rgQueues == NULL) hr = E_OUTOFMEMORY;
  808. }
  809. }
  810. if (SUCCEEDED(hr))
  811. {
  812. *prgQueues = rgQueues;
  813. *pcQueues = cQueues;
  814. }
  815. else
  816. {
  817. *prgQueues = NULL;
  818. *pcQueues = 0;
  819. if (rgQueues) MIDL_user_free(rgQueues);
  820. }
  821. paqrpc->ShutdownUnlock();
  822. pIAdvQueueAdmin->Release();
  823. paqrpc->Release();
  824. }
  825. TraceFunctLeave();
  826. return hr;
  827. }
  828. NET_API_STATUS
  829. NET_API_FUNCTION
  830. AQGetMessageProperties(
  831. AQUEUE_HANDLE wszServer,
  832. LPWSTR wszInstance,
  833. QUEUELINK_ID *pqlQueueLinkId,
  834. MESSAGE_ENUM_FILTER *pmfMessageEnumFilter,
  835. DWORD *pcMsgs,
  836. MESSAGE_INFO **prgMsgs)
  837. {
  838. TraceFunctEnter("AQGetMessageProperties");
  839. CAQRpcSvrInst *paqrpc = NULL;
  840. HRESULT hr = S_OK;
  841. IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
  842. if (IsBadReadPtr((LPVOID)pqlQueueLinkId, sizeof(QUEUELINK_ID)))
  843. {
  844. ErrorTrace(NULL, "Invalid parameter: pqlQueueLinkId\n");
  845. TraceFunctLeave();
  846. return(E_INVALIDARG);
  847. }
  848. if (IsBadReadPtr((LPVOID)pmfMessageEnumFilter, sizeof(MESSAGE_FILTER)))
  849. {
  850. ErrorTrace(NULL, "Invalid parameter: pmfMessageEnumFilter\n");
  851. TraceFunctLeave();
  852. return(E_INVALIDARG);
  853. }
  854. if (IsBadWritePtr((LPVOID)pcMsgs, sizeof(DWORD)))
  855. {
  856. ErrorTrace(NULL, "Invalid parameter: pcMsgs\n");
  857. TraceFunctLeave();
  858. return(E_INVALIDARG);
  859. }
  860. if (IsBadWritePtr((LPVOID)prgMsgs, sizeof(MESSAGE_INFO *)))
  861. {
  862. ErrorTrace(NULL, "Invalid parameter: prgMsgs\n");
  863. TraceFunctLeave();
  864. return(E_INVALIDARG);
  865. }
  866. hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc);
  867. if (SUCCEEDED(hr))
  868. {
  869. MESSAGE_INFO *rgMsgs = NULL;
  870. DWORD cMsgs = 0;
  871. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  872. // loop on calls to GetLinkIDs until we have enough memory to
  873. // get all of the links. for the first call we will always
  874. // have a NULL rgMsgs and just be asking for the size. we need
  875. // to loop in case more links show up between calls
  876. while (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
  877. {
  878. hr = pIAdvQueueAdmin->GetMessageProperties(pqlQueueLinkId,
  879. pmfMessageEnumFilter,
  880. &cMsgs,
  881. rgMsgs);
  882. if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
  883. {
  884. if (rgMsgs != NULL) MIDL_user_free(rgMsgs);
  885. rgMsgs = (MESSAGE_INFO *)
  886. MIDL_user_allocate(sizeof(MESSAGE_INFO) * cMsgs);
  887. if (rgMsgs == NULL) hr = E_OUTOFMEMORY;
  888. }
  889. }
  890. if (SUCCEEDED(hr))
  891. {
  892. *prgMsgs = rgMsgs;
  893. *pcMsgs = cMsgs;
  894. }
  895. else
  896. {
  897. *prgMsgs = NULL;
  898. *pcMsgs = 0;
  899. if (rgMsgs) MIDL_user_free(rgMsgs);
  900. }
  901. paqrpc->ShutdownUnlock();
  902. pIAdvQueueAdmin->Release();
  903. paqrpc->Release();
  904. }
  905. TraceFunctLeave();
  906. return hr;
  907. }
  908. //---[ AQQuerySupportedActions ]----------------------------------------------
  909. //
  910. //
  911. // Description:
  912. // Client stub for querying supported actions
  913. // Parameters:
  914. // IN wszServer The server to connect to
  915. // IN wszInstance The virtual server instance to connect to
  916. // IN pqlQueueLinkId The queue/link we are interested in
  917. // OUT pdwSupportedActions The MESSAGE_ACTION flags supported
  918. // OUT pdwSupportedFilterFlags The supported filter flags
  919. // Returns:
  920. // S_OK on success
  921. // E_INVALIDARG on bad pointer args
  922. // Internal error code from HrGetAQInstance or
  923. // IAdvQueue::QuerySupportedActions
  924. // History:
  925. // 6/15/99 - MikeSwa Created
  926. //
  927. //-----------------------------------------------------------------------------
  928. NET_API_STATUS
  929. NET_API_FUNCTION
  930. AQQuerySupportedActions(
  931. LPWSTR wszServer,
  932. LPWSTR wszInstance,
  933. QUEUELINK_ID *pqlQueueLinkId,
  934. DWORD *pdwSupportedActions,
  935. DWORD *pdwSupportedFilterFlags)
  936. {
  937. TraceFunctEnter("AQQuerySupportedActions");
  938. CAQRpcSvrInst *paqrpc = NULL;
  939. HRESULT hr = S_OK;
  940. IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
  941. BOOL fHasWriteAccess = TRUE;
  942. if (IsBadReadPtr((LPVOID)pqlQueueLinkId, sizeof(QUEUELINK_ID)))
  943. {
  944. ErrorTrace(NULL, "Invalid parameter: pqlQueueLinkId\n");
  945. TraceFunctLeave();
  946. return(E_INVALIDARG);
  947. }
  948. if (IsBadWritePtr((LPVOID)pdwSupportedActions, sizeof(DWORD)))
  949. {
  950. ErrorTrace(NULL, "Invalid parameter: pdwSupportedActions\n");
  951. TraceFunctLeave();
  952. return(E_INVALIDARG);
  953. }
  954. if (IsBadWritePtr((LPVOID)pdwSupportedFilterFlags, sizeof(DWORD)))
  955. {
  956. ErrorTrace(NULL, "Invalid parameter: pdwSupportedFilterFlags\n");
  957. TraceFunctLeave();
  958. return(E_INVALIDARG);
  959. }
  960. hr = HrGetAQInstance(wszInstance, TRUE, &pIAdvQueueAdmin, &paqrpc);
  961. if (FAILED(hr) && (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) != hr))
  962. return hr;
  963. //
  964. // If we cannot get the instance, then try again only requesting
  965. // read-only access
  966. //
  967. if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr)
  968. {
  969. fHasWriteAccess = FALSE;
  970. hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc);
  971. }
  972. if (SUCCEEDED(hr))
  973. {
  974. hr = pIAdvQueueAdmin->QuerySupportedActions(pqlQueueLinkId,
  975. pdwSupportedActions,
  976. pdwSupportedFilterFlags);
  977. paqrpc->ShutdownUnlock();
  978. pIAdvQueueAdmin->Release();
  979. paqrpc->Release();
  980. //
  981. // If the caller does not have write access, we need to
  982. // censor the supported actions
  983. //
  984. if (!fHasWriteAccess)
  985. *pdwSupportedActions = 0;
  986. }
  987. TraceFunctLeave();
  988. return hr;
  989. }
  990. //---[ MIDL_user_allocate ]----------------------------------------------------
  991. //
  992. //
  993. // Description:
  994. // MIDL memory allocation
  995. // Parameters:
  996. // size : Memory size requested.
  997. // Returns:
  998. // Pointer to the allocated memory block.
  999. // History:
  1000. // 6/5/99 - MikeSwa Created (taken from smtpapi rcputil.c)
  1001. //
  1002. //-----------------------------------------------------------------------------
  1003. PVOID MIDL_user_allocate(IN size_t size)
  1004. {
  1005. PVOID pvBlob = NULL;
  1006. pvBlob = LocalAlloc( LPTR, size);
  1007. return(pvBlob);
  1008. }
  1009. //---[ MIDL_user_free ]--------------------------------------------------------
  1010. //
  1011. //
  1012. // Description:
  1013. // MIDL memory free .
  1014. // Parameters:
  1015. // IN pvBlob Pointer to a memory block that is freed.
  1016. // Returns:
  1017. // -
  1018. // History:
  1019. // 6/5/99 - MikeSwa Created (from smtpapi rcputil.c)
  1020. //
  1021. //-----------------------------------------------------------------------------
  1022. VOID MIDL_user_free(IN PVOID pvBlob)
  1023. {
  1024. LocalFree(pvBlob);
  1025. }