|
|
//-----------------------------------------------------------------------------
//
//
// File: aqrpcsvr.cpp
//
// Description: Implementation of AQ RPC server
//
// Author: Mike Swafford (MikeSwa)
//
// History:
// 6/5/99 - MikeSwa Created
//
// Copyright (C) 1999 Microsoft Corporation
//
//-----------------------------------------------------------------------------
#include "aqprecmp.h"
#include "aqrpcsvr.h"
#include "aqadmrpc.h"
#include <inetcom.h>
#include <iiscnfg.h>
LIST_ENTRY CAQRpcSvrInst::s_liInstancesHead; CShareLockNH CAQRpcSvrInst::s_slPrivateData; RPC_BINDING_VECTOR *CAQRpcSvrInst::s_pRpcBindingVector = NULL; BOOL CAQRpcSvrInst::s_fEndpointsRegistered = FALSE;
//
// Quick and dirty string validation
//
static inline BOOL pValidateStringPtr(LPWSTR lpwszString, DWORD dwMaxLength) { if (IsBadStringPtr((LPCTSTR)lpwszString, dwMaxLength)) return(FALSE); while (dwMaxLength--) if (*lpwszString++ == 0) return(TRUE); return(FALSE); }
//---[ HrInitializeAQRpc ]-----------------------------------------------------
//
//
// Description:
// Initializes AQ RPC. This should only be called once per service
// startup (not VS). Caller in responable for ensuring that this and
// HrInitializeAQRpc are called in a thread safe manner.
// Parameters:
// -
// Returns:
// S_OK on success
// Error code from RPC
// History:
// 6/5/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
HRESULT CAQRpcSvrInst::HrInitializeAQRpc() { TraceFunctEnterEx((LPARAM) NULL, "CAQRpcSvrInst::HrInitializeAQRpc"); HRESULT hr = S_OK; RPC_STATUS status = RPC_S_OK;
InitializeListHead(&s_liInstancesHead); s_pRpcBindingVector = NULL; s_fEndpointsRegistered = FALSE;
//Listen on the appropriate protocols sequences
status = RpcServerUseAllProtseqs(RPC_C_PROTSEQ_MAX_REQS_DEFAULT, NULL);
if (status != RPC_S_OK) goto Exit;
//Advertise the appropriate interface
status = RpcServerRegisterIfEx(IAQAdminRPC_v1_0_s_ifspec, NULL, NULL, RPC_IF_AUTOLISTEN, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, NULL);
if (status != RPC_S_OK) goto Exit;
//Get the dynamic endpoints
status = RpcServerInqBindings(&s_pRpcBindingVector); if (status != RPC_S_OK) goto Exit;
//Register the endpoints
status = RpcEpRegister(IAQAdminRPC_v1_0_s_ifspec, s_pRpcBindingVector, NULL, NULL); if (status != RPC_S_OK) goto Exit;
s_fEndpointsRegistered = TRUE;
Exit: if (status != RPC_S_OK) hr = HRESULT_FROM_WIN32(status);
TraceFunctLeave(); return hr; }
//---[ HrDeinitializeAQRpc ]----------------------------------------------------
//
//
// Description:
// Do global RPC cleanup
// Parameters:
// -
// Returns:
// S_OK on success
// Error code from RPC otherwise
// History:
// 6/5/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
HRESULT CAQRpcSvrInst::HrDeinitializeAQRpc() { TraceFunctEnterEx((LPARAM) NULL, "CAQRpcSvrInst::HrDeinitializeAQRpc"); HRESULT hr = S_OK; RPC_STATUS status = RPC_S_OK;
if (s_fEndpointsRegistered) { status = RpcEpUnregister(IAQAdminRPC_v1_0_s_ifspec, s_pRpcBindingVector, NULL); if (status != RPC_S_OK) hr = HRESULT_FROM_WIN32(status); }
if (s_pRpcBindingVector) { status = RpcBindingVectorFree(&s_pRpcBindingVector); if (status != RPC_S_OK) hr = HRESULT_FROM_WIN32(status); }
status = RpcServerUnregisterIf(IAQAdminRPC_v1_0_s_ifspec, NULL, 0);
if (status != RPC_S_OK) hr = HRESULT_FROM_WIN32(status);
s_fEndpointsRegistered = FALSE; s_pRpcBindingVector = NULL; TraceFunctLeave(); return hr; }
//---[ HrInitializeAQServerInstanceRPC ]---------------------------------------
//
//
// Description:
// Add instance to RPC interface
// Parameters:
// IN paqinst Instnace to add to interface
// IN dwVirtualServerID Virtual server ID of instance
// Returns:
// S_OK on success
// History:
// 6/5/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
HRESULT CAQRpcSvrInst::HrInitializeAQServerInstanceRPC(CAQSvrInst *paqinst, DWORD dwVirtualServerID, ISMTPServer *pISMTPServer) { TraceFunctEnterEx((LPARAM) paqinst, "CAQRpcSvrInst::HrInitializeAQServerInstanceRPC"); HRESULT hr = S_OK; CAQRpcSvrInst *paqrpc = NULL;
paqrpc = CAQRpcSvrInst::paqrpcGetRpcSvrInstance(dwVirtualServerID); if (paqrpc) { _ASSERT(0 && "Instance already added to RPC interface"); paqrpc->Release(); paqrpc = NULL; goto Exit; }
paqrpc = new CAQRpcSvrInst(paqinst, dwVirtualServerID, pISMTPServer); if (!paqrpc) { hr = E_OUTOFMEMORY; goto Exit; }
Exit: TraceFunctLeave(); return hr; }
//---[ HrDeinitializeAQServerInstanceRPC ]-------------------------------------
//
//
// Description:
// Remove instance from RPC interface
// Parameters:
// IN paqinst Instnace to remove from interface
// IN dwVirtualServerID Virtual server ID of instance
// Returns:
// S_OK on success
// History:
// 6/5/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
HRESULT CAQRpcSvrInst::HrDeinitializeAQServerInstanceRPC(CAQSvrInst *paqinst, DWORD dwVirtualServerID) { TraceFunctEnterEx((LPARAM) paqinst, "CAQRpcSvrInst::HrDeinitializeAQServerInstanceRPC"); HRESULT hr = S_OK; CAQRpcSvrInst *paqrpc = NULL;
paqrpc = CAQRpcSvrInst::paqrpcGetRpcSvrInstance(dwVirtualServerID); if (!paqrpc) goto Exit; //allow calls if HrInitializeAQServerInstanceRPC failed
//Found it
//$$TODO - verify the paqinst is correct
paqrpc->SignalShutdown();
//Remove from list of entries
s_slPrivateData.ExclusiveLock(); RemoveEntryList(&(paqrpc->m_liInstances)); s_slPrivateData.ExclusiveUnlock(); paqrpc->Release(); //release reference associated with list
Exit: if (paqrpc) paqrpc->Release();
TraceFunctLeave(); return hr; }
//---[ CAQRpcSvrInst::CAQRpcSvrInst ]------------------------------------------
//
//
// Description:
// Constructor for CAQRpcSvrInst class
// Parameters:
// IN paqinst Instnace to remove from interface
// IN dwVirtualServerID Virtual server ID of instance
// Returns:
// -
// History:
// 6/6/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAQRpcSvrInst::CAQRpcSvrInst(CAQSvrInst *paqinst, DWORD dwVirtualServerID, ISMTPServer *pISMTPServer) { _ASSERT(paqinst); _ASSERT(pISMTPServer);
m_paqinst = paqinst; m_dwVirtualServerID = dwVirtualServerID; m_pISMTPServer = pISMTPServer; m_dwSignature = CAQRpcSvrInst_Sig;
if (m_paqinst) m_paqinst->AddRef();
if (m_pISMTPServer) m_pISMTPServer->AddRef();
//Add to list of virtual server instaces
s_slPrivateData.ExclusiveLock(); InsertHeadList(&s_liInstancesHead, &m_liInstances); s_slPrivateData.ExclusiveUnlock(); }
//---[ CAQRpcSvrInst::~CAQRpcSvrInst ]-----------------------------------------
//
//
// Description:
// Desctructor for CAQRpcSvrInst
// Parameters:
// -
// Returns:
// -
// History:
// 6/6/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAQRpcSvrInst::~CAQRpcSvrInst() {
if (m_paqinst) m_paqinst->Release();
if (m_pISMTPServer) m_pISMTPServer->Release();
m_dwSignature = CAQRpcSvrInst_SigFree;
}
//---[ CAQRpcSvrInst::paqrpcGetRpcSvrInstance ]--------------------------------
//
//
// Description:
// Gets the CAQRpcSvrInst for a given virtual server ID
// Parameters:
// IN dwVirtualServerID Virtual server ID of instance
// Returns:
// Pointer to appropriate CAQRpcSvrInst on success
// NULL if not found
// History:
// 6/6/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAQRpcSvrInst *CAQRpcSvrInst::paqrpcGetRpcSvrInstance(DWORD dwVirtualServerID) { LIST_ENTRY *pli = NULL; CAQRpcSvrInst *paqrpc = NULL;
s_slPrivateData.ShareLock(); pli = s_liInstancesHead.Flink;
while (pli && (pli != &s_liInstancesHead)) { paqrpc = CONTAINING_RECORD(pli, CAQRpcSvrInst, m_liInstances); //$$TODO check signature
if (paqrpc->m_dwVirtualServerID == dwVirtualServerID) { paqrpc->AddRef(); break; //found it
}
paqrpc = NULL; pli = pli->Flink; } s_slPrivateData.ShareUnlock();
return paqrpc; }
//---[ CAQRpcSvrInst::fAccessCheck ]-------------------------------------------
//
//
// Description:
// Performs acess check for RPC interfaces
// Parameters:
// IN fWriteAccessRequired TRUE if write access is required
// Returns:
// TRUE if access check is succeeds
// FALSE if user does not have access
// History:
// 6/7/99 - MikeSwa Created (from SMTP AQAdmin access code)
//
//-----------------------------------------------------------------------------
BOOL CAQRpcSvrInst::fAccessCheck(BOOL fWriteAccessRequired) { TraceFunctEnterEx((LPARAM) this, "CAQRpcSvrInst::fAccessCheck"); SECURITY_DESCRIPTOR *pSecurityDescriptor = NULL; DWORD cbSecurityDescriptor = 0; HRESULT hr = S_OK; DWORD err = ERROR_SUCCESS; BOOL fAccessAllowed = FALSE; HANDLE hAccessToken = NULL; BYTE PrivSet[200]; DWORD cbPrivSet = sizeof(PrivSet); ACCESS_MASK maskAccessGranted; GENERIC_MAPPING gmGenericMapping = { MD_ACR_READ, MD_ACR_WRITE, MD_ACR_READ, MD_ACR_READ | MD_ACR_WRITE };
if (!m_pISMTPServer) goto Exit; //if we cannot check it... assume if fails
hr = m_pISMTPServer->ReadMetabaseData(MD_ADMIN_ACL, NULL, &cbSecurityDescriptor); if (SUCCEEDED(hr)) { //We passed in NULL.. should have failed
_ASSERT(0 && "Invalid response for ReadMetabaseData"); goto Exit; } if ((HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr) || !cbSecurityDescriptor) { //Can't get ACL... bail
goto Exit; }
pSecurityDescriptor = (SECURITY_DESCRIPTOR *) pvMalloc(cbSecurityDescriptor); if (!pSecurityDescriptor) goto Exit;
hr = m_pISMTPServer->ReadMetabaseData(MD_ADMIN_ACL, (BYTE *) pSecurityDescriptor, &cbSecurityDescriptor); if (FAILED(hr)) { ErrorTrace((LPARAM) this, "Error calling ReadMetabaseData for AccessCheck - hr 0x%08X", hr); goto Exit; }
// Verify that we got a proper SD. if not then fail
if (!IsValidSecurityDescriptor(pSecurityDescriptor)) { ErrorTrace(0, "IsValidSecurityDescriptor failed with %lu", GetLastError()); goto Exit; }
err = RpcImpersonateClient(NULL); if (err != ERROR_SUCCESS) { ErrorTrace((LPARAM) this, "RpcImpersonateClient failed with %lu", err); goto Exit; }
if (!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hAccessToken)) { ErrorTrace((LPARAM) this, "OpenThreadToken Failed with %lu", GetLastError()); goto Exit; }
//Check access
if (!AccessCheck(pSecurityDescriptor, hAccessToken, fWriteAccessRequired ? MD_ACR_WRITE : MD_ACR_READ, &gmGenericMapping, (PRIVILEGE_SET *)PrivSet, &cbPrivSet, &maskAccessGranted, &fAccessAllowed)) { fAccessAllowed = FALSE; ErrorTrace((LPARAM) this, "AccessCheck Failed with %lu", GetLastError()); goto Exit; }
if (!fAccessAllowed) DebugTrace((LPARAM) this, "Access denied for Queue Admin RPC");
//Do any additional read-only processing
if (fWriteAccessRequired && fAccessAllowed && !(MD_ACR_WRITE & maskAccessGranted)) { DebugTrace((LPARAM) this, "Write Access denied for Queue Admin RPC"); fAccessAllowed = FALSE; }
Exit: if (pSecurityDescriptor) FreePv(pSecurityDescriptor);
if (hAccessToken) CloseHandle(hAccessToken);
TraceFunctLeave(); return fAccessAllowed; }
//---[ HrGetAQInstance ]-------------------------------------------------------
//
//
// Description:
// This is used by all of the AQ RPC's to get a pointer to AQ based on an
// instance name.
//
// THE SHUTDOWN LOCK ON ppaqrpc IS HELD AFTER THIS CALL COMPLETES.
// THE CALLER MUST CALL paqrpc->ShutdownUnlock() WHEN THEY HAVE
// FINISHED THEIR QUEUE ADMIN OPERATION.
// Parameters:
// IN wszInstance A number containing the instance to lookup.
// IN fWriteAccessRequired TRUE if write access is required
// OUT ppIAdvQueueAdmin Pointer to AQ admin interface
// OUT ppaqrpc Pointer to CAQRpcSvrInst
// Returns:
// S_OK on success
// HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) if user does not have access
// HRESULT_FROM_WIN32(ERROR_NOT_FOUND) if virtual server is not found
// HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) if server is shutting
// down.
// E_POINTER if pointer arguments are NULL
// E_INVALIDARG if wszInstance is a bad pointer
// History:
// 6/11/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
HRESULT HrGetAQInstance(IN LPWSTR wszInstance, IN BOOL fWriteAccessRequired, OUT IAdvQueueAdmin **ppIAdvQueueAdmin, OUT CAQRpcSvrInst **ppaqrpc) { TraceFunctEnter("GetAQInstance");
CAQSvrInst *paqinst = NULL; IAdvQueueAdmin *pIAdvQueueAdmin = NULL; CAQRpcSvrInst *paqrpc = NULL; BOOL fHasAccess = FALSE; DWORD dwInstance = 1; BOOL fShutdownLock = FALSE; HRESULT hr = S_OK;
_ASSERT(ppIAdvQueueAdmin); _ASSERT(ppaqrpc);
if (!wszInstance || !ppIAdvQueueAdmin || !ppaqrpc) { hr = E_POINTER; goto Exit; }
*ppIAdvQueueAdmin = NULL; *ppaqrpc = NULL;
if (!pValidateStringPtr(wszInstance, MAX_PATH)) { ErrorTrace(NULL, "Invalid parameter: wszInstance\n"); hr = E_INVALIDARG; goto Exit; }
dwInstance = _wtoi(wszInstance); DebugTrace((LPARAM) NULL, "instance is %S (%i)", wszInstance, dwInstance);
paqrpc = CAQRpcSvrInst::paqrpcGetRpcSvrInstance(dwInstance); if (!paqrpc) { ErrorTrace((LPARAM) NULL, "Error unable to find requested virtual server for QAPI %d", dwInstance); hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); goto Exit; }
//
// Check for proper access.
//
// This should be done BEFORE the shutdown lock is grabbed because it
// may require hitting the metabase (which could cause a shutdown deadlock)
if (!paqrpc->fAccessCheck(fWriteAccessRequired)) { hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); goto Exit; }
// Ensure that shutdown does not happen in the middle of our operation
if (!paqrpc->fTryShutdownLock()) { hr = HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE); goto Exit; }
fShutdownLock = TRUE; paqinst = paqrpc->paqinstGetAQ();
hr = paqinst->QueryInterface(IID_IAdvQueueAdmin, (void **) &pIAdvQueueAdmin); if (FAILED(hr)) { pIAdvQueueAdmin = NULL; goto Exit; }
Exit:
if (FAILED(hr)) { //cleanup
if (paqrpc) { if (fShutdownLock) paqrpc->ShutdownUnlock(); paqrpc->Release(); }
if (pIAdvQueueAdmin) pIAdvQueueAdmin->Release(); pIAdvQueueAdmin = NULL; } else //return OUT params
{ *ppIAdvQueueAdmin = pIAdvQueueAdmin; *ppaqrpc = paqrpc; _ASSERT(ppaqrpc); _ASSERT(pIAdvQueueAdmin); }
TraceFunctLeave(); return hr; }
NET_API_STATUS NET_API_FUNCTION AQApplyActionToLinks( AQUEUE_HANDLE wszServer, LPWSTR wszInstance, LINK_ACTION laAction) { TraceFunctEnter("AQApplyActionToLinks"); HRESULT hr = S_OK; IAdvQueueAdmin *pIAdvQueueAdmin = NULL; CAQRpcSvrInst *paqrpc = NULL; BOOL fNeedWriteAccess = TRUE;
if (LA_INTERNAL == laAction) //just checking the state
fNeedWriteAccess = FALSE;
hr = HrGetAQInstance(wszInstance, fNeedWriteAccess, &pIAdvQueueAdmin, &paqrpc); if (FAILED(hr)) return hr;
hr = pIAdvQueueAdmin->ApplyActionToLinks(laAction);
paqrpc->ShutdownUnlock(); paqrpc->Release(); pIAdvQueueAdmin->Release();
TraceFunctLeave(); return hr; }
NET_API_STATUS NET_API_FUNCTION AQApplyActionToMessages( AQUEUE_HANDLE wszServer, LPWSTR wszInstance, QUEUELINK_ID *pqlQueueLinkId, MESSAGE_FILTER *pmfMessageFilter, MESSAGE_ACTION maMessageAction, DWORD *pcMsgs) { TraceFunctEnter("AQApplyActionToMessages"); CAQRpcSvrInst *paqrpc = NULL; HRESULT hr = S_OK; IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
if (IsBadReadPtr((LPVOID)pqlQueueLinkId, sizeof(QUEUELINK_ID))) { ErrorTrace(NULL, "Invalid parameter: pqlQueueLinkId\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadReadPtr((LPVOID)pmfMessageFilter, sizeof(MESSAGE_FILTER))) { ErrorTrace(NULL, "Invalid parameter: pmfMessageFilter\n"); TraceFunctLeave(); return(E_INVALIDARG); }
hr = HrGetAQInstance(wszInstance, TRUE, &pIAdvQueueAdmin, &paqrpc); if (SUCCEEDED(hr)) { hr = pIAdvQueueAdmin->ApplyActionToMessages(pqlQueueLinkId, pmfMessageFilter, maMessageAction, pcMsgs); paqrpc->ShutdownUnlock(); pIAdvQueueAdmin->Release(); paqrpc->Release(); }
TraceFunctLeave(); return hr; }
NET_API_STATUS NET_API_FUNCTION AQGetQueueInfo( AQUEUE_HANDLE wszServer, LPWSTR wszInstance, QUEUELINK_ID *pqlQueueId, QUEUE_INFO *pqiQueueInfo) { TraceFunctEnter("AQGetQueueInfo"); CAQRpcSvrInst *paqrpc = NULL; HRESULT hr = S_OK; IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
if (IsBadReadPtr((LPVOID)pqlQueueId, sizeof(QUEUELINK_ID))) { ErrorTrace(NULL, "Invalid parameter: pqlQueueId\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadReadPtr((LPVOID)pqiQueueInfo, sizeof(QUEUE_INFO))) { ErrorTrace(NULL, "Invalid parameter: pqiQueueInfo\n"); TraceFunctLeave(); return(E_INVALIDARG); }
hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc); if (SUCCEEDED(hr)) { hr = pIAdvQueueAdmin->GetQueueInfo(pqlQueueId, pqiQueueInfo); paqrpc->ShutdownUnlock(); pIAdvQueueAdmin->Release(); paqrpc->Release(); }
TraceFunctLeave(); return hr; }
NET_API_STATUS NET_API_FUNCTION AQGetLinkInfo( AQUEUE_HANDLE wszServer, LPWSTR wszInstance, QUEUELINK_ID *pqlLinkId, LINK_INFO *pliLinkInfo, HRESULT *phrLinkDiagnostic) { TraceFunctEnter("AQGetLinkInfo"); CAQRpcSvrInst *paqrpc = NULL; HRESULT hr = S_OK; IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
if (IsBadReadPtr((LPVOID)pqlLinkId, sizeof(QUEUELINK_ID))) { ErrorTrace(NULL, "Invalid parameter: pqlLinkId\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadReadPtr((LPVOID)pliLinkInfo, sizeof(LINK_INFO))) { ErrorTrace(NULL, "Invalid parameter: pliLinkInfo\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadWritePtr((LPVOID)phrLinkDiagnostic, sizeof(HRESULT))) { ErrorTrace(NULL, "Invalid parameter: pliLinkInfo\n"); TraceFunctLeave(); return(E_INVALIDARG); }
hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc); if (SUCCEEDED(hr)) { hr = pIAdvQueueAdmin->GetLinkInfo(pqlLinkId, pliLinkInfo, phrLinkDiagnostic); paqrpc->ShutdownUnlock(); pIAdvQueueAdmin->Release(); paqrpc->Release(); }
// X5:195608
// I'm pretty sure the root of this has been fixed in fRPCCopyName but
// just to be sure we are Firewalling against the problem here
// and in vsaqlink.cpp
if(SUCCEEDED(hr) && pliLinkInfo && !pliLinkInfo->szLinkName) { // ASSERT this so we can catch it internally
_ASSERT(0 && "AQGetLinkInfo wants to return success with a NULL szLinkName");
// return a failure because we do not have a link name - I'm going
// with AQUEUE_E_INVALID_DOMAIN to prevent an admin popup
hr = AQUEUE_E_INVALID_DOMAIN; }
TraceFunctLeave(); return hr; }
NET_API_STATUS NET_API_FUNCTION AQSetLinkState( AQUEUE_HANDLE wszServer, LPWSTR wszInstance, QUEUELINK_ID *pqlLinkId, LINK_ACTION la) { TraceFunctEnter("AQSetLinkInfo"); CAQRpcSvrInst *paqrpc = NULL; HRESULT hr = S_OK; IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
if (IsBadReadPtr((LPVOID)pqlLinkId, sizeof(QUEUELINK_ID))) { ErrorTrace(NULL, "Invalid parameter: pqlLinkId\n"); TraceFunctLeave(); return(E_INVALIDARG); }
hr = HrGetAQInstance(wszInstance, TRUE, &pIAdvQueueAdmin, &paqrpc); if (SUCCEEDED(hr)) { hr = pIAdvQueueAdmin->SetLinkState(pqlLinkId, la); paqrpc->ShutdownUnlock(); pIAdvQueueAdmin->Release(); paqrpc->Release(); }
TraceFunctLeave(); return hr; }
NET_API_STATUS NET_API_FUNCTION AQGetLinkIDs( AQUEUE_HANDLE wszServer, LPWSTR wszInstance, DWORD *pcLinks, QUEUELINK_ID **prgLinks) { TraceFunctEnter("AQGetLinkIDs"); CAQRpcSvrInst *paqrpc = NULL; HRESULT hr = S_OK; IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
if (IsBadWritePtr((LPVOID)pcLinks, sizeof(DWORD))) { ErrorTrace(NULL, "Invalid parameter: pcLinks\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadWritePtr((LPVOID)prgLinks, sizeof(QUEUELINK_ID *))) { ErrorTrace(NULL, "Invalid parameter: prgLinks\n"); TraceFunctLeave(); return(E_INVALIDARG); }
hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc); if (SUCCEEDED(hr)) { QUEUELINK_ID *rgLinks = NULL; DWORD cLinks = 0; hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
// loop on calls to GetLinkIDs until we have enough memory to
// get all of the links. for the first call we will always
// have a NULL rgLinks and just be asking for the size. we need
// to loop in case more links show up between calls
while (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { hr = pIAdvQueueAdmin->GetLinkIDs(&cLinks, rgLinks); if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { if (rgLinks != NULL) MIDL_user_free(rgLinks); rgLinks = (QUEUELINK_ID *) MIDL_user_allocate(sizeof(QUEUELINK_ID) * cLinks); if (rgLinks == NULL) hr = E_OUTOFMEMORY; } }
if (SUCCEEDED(hr)) { *prgLinks = rgLinks; *pcLinks = cLinks; } else { *prgLinks = NULL; *pcLinks = 0; if (rgLinks) MIDL_user_free(rgLinks); } paqrpc->ShutdownUnlock(); pIAdvQueueAdmin->Release(); paqrpc->Release(); }
TraceFunctLeave(); return hr; }
NET_API_STATUS NET_API_FUNCTION AQGetQueueIDs( AQUEUE_HANDLE wszServer, LPWSTR wszInstance, QUEUELINK_ID *pqlLinkId, DWORD *pcQueues, QUEUELINK_ID **prgQueues) { TraceFunctEnter("AQGetQueueIDs"); CAQRpcSvrInst *paqrpc = NULL; HRESULT hr = S_OK; IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
if (IsBadReadPtr((LPVOID)pqlLinkId, sizeof(QUEUELINK_ID))) { ErrorTrace(NULL, "Invalid parameter: pqlLinkId\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadWritePtr((LPVOID)pcQueues, sizeof(DWORD))) { ErrorTrace(NULL, "Invalid parameter: pcQueues\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadWritePtr((LPVOID)prgQueues, sizeof(QUEUELINK_ID *))) { ErrorTrace(NULL, "Invalid parameter: prgQueues\n"); TraceFunctLeave(); return(E_INVALIDARG); }
hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc); if (SUCCEEDED(hr)) { QUEUELINK_ID *rgQueues = NULL; DWORD cQueues = 0; hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
// loop on calls to GetLinkIDs until we have enough memory to
// get all of the links. for the first call we will always
// have a NULL rgQueues and just be asking for the size. we need
// to loop in case more links show up between calls
while (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { hr = pIAdvQueueAdmin->GetQueueIDs(pqlLinkId, &cQueues, rgQueues); if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { if (rgQueues != NULL) MIDL_user_free(rgQueues); rgQueues = (QUEUELINK_ID *) MIDL_user_allocate(sizeof(QUEUELINK_ID) * cQueues); if (rgQueues == NULL) hr = E_OUTOFMEMORY; } }
if (SUCCEEDED(hr)) { *prgQueues = rgQueues; *pcQueues = cQueues; } else { *prgQueues = NULL; *pcQueues = 0; if (rgQueues) MIDL_user_free(rgQueues); } paqrpc->ShutdownUnlock(); pIAdvQueueAdmin->Release(); paqrpc->Release(); }
TraceFunctLeave(); return hr; }
NET_API_STATUS NET_API_FUNCTION AQGetMessageProperties( AQUEUE_HANDLE wszServer, LPWSTR wszInstance, QUEUELINK_ID *pqlQueueLinkId, MESSAGE_ENUM_FILTER *pmfMessageEnumFilter, DWORD *pcMsgs, MESSAGE_INFO **prgMsgs) { TraceFunctEnter("AQGetMessageProperties"); CAQRpcSvrInst *paqrpc = NULL; HRESULT hr = S_OK; IAdvQueueAdmin *pIAdvQueueAdmin = NULL;
if (IsBadReadPtr((LPVOID)pqlQueueLinkId, sizeof(QUEUELINK_ID))) { ErrorTrace(NULL, "Invalid parameter: pqlQueueLinkId\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadReadPtr((LPVOID)pmfMessageEnumFilter, sizeof(MESSAGE_FILTER))) { ErrorTrace(NULL, "Invalid parameter: pmfMessageEnumFilter\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadWritePtr((LPVOID)pcMsgs, sizeof(DWORD))) { ErrorTrace(NULL, "Invalid parameter: pcMsgs\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadWritePtr((LPVOID)prgMsgs, sizeof(MESSAGE_INFO *))) { ErrorTrace(NULL, "Invalid parameter: prgMsgs\n"); TraceFunctLeave(); return(E_INVALIDARG); }
hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc); if (SUCCEEDED(hr)) { MESSAGE_INFO *rgMsgs = NULL; DWORD cMsgs = 0; hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
// loop on calls to GetLinkIDs until we have enough memory to
// get all of the links. for the first call we will always
// have a NULL rgMsgs and just be asking for the size. we need
// to loop in case more links show up between calls
while (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { hr = pIAdvQueueAdmin->GetMessageProperties(pqlQueueLinkId, pmfMessageEnumFilter, &cMsgs, rgMsgs); if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { if (rgMsgs != NULL) MIDL_user_free(rgMsgs); rgMsgs = (MESSAGE_INFO *) MIDL_user_allocate(sizeof(MESSAGE_INFO) * cMsgs); if (rgMsgs == NULL) hr = E_OUTOFMEMORY; } }
if (SUCCEEDED(hr)) { *prgMsgs = rgMsgs; *pcMsgs = cMsgs; } else { *prgMsgs = NULL; *pcMsgs = 0; if (rgMsgs) MIDL_user_free(rgMsgs); } paqrpc->ShutdownUnlock(); pIAdvQueueAdmin->Release(); paqrpc->Release(); }
TraceFunctLeave(); return hr; }
//---[ AQQuerySupportedActions ]----------------------------------------------
//
//
// Description:
// Client stub for querying supported actions
// Parameters:
// IN wszServer The server to connect to
// IN wszInstance The virtual server instance to connect to
// IN pqlQueueLinkId The queue/link we are interested in
// OUT pdwSupportedActions The MESSAGE_ACTION flags supported
// OUT pdwSupportedFilterFlags The supported filter flags
// Returns:
// S_OK on success
// E_INVALIDARG on bad pointer args
// Internal error code from HrGetAQInstance or
// IAdvQueue::QuerySupportedActions
// History:
// 6/15/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
NET_API_STATUS NET_API_FUNCTION AQQuerySupportedActions( LPWSTR wszServer, LPWSTR wszInstance, QUEUELINK_ID *pqlQueueLinkId, DWORD *pdwSupportedActions, DWORD *pdwSupportedFilterFlags) { TraceFunctEnter("AQQuerySupportedActions"); CAQRpcSvrInst *paqrpc = NULL; HRESULT hr = S_OK; IAdvQueueAdmin *pIAdvQueueAdmin = NULL; BOOL fHasWriteAccess = TRUE;
if (IsBadReadPtr((LPVOID)pqlQueueLinkId, sizeof(QUEUELINK_ID))) { ErrorTrace(NULL, "Invalid parameter: pqlQueueLinkId\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadWritePtr((LPVOID)pdwSupportedActions, sizeof(DWORD))) { ErrorTrace(NULL, "Invalid parameter: pdwSupportedActions\n"); TraceFunctLeave(); return(E_INVALIDARG); }
if (IsBadWritePtr((LPVOID)pdwSupportedFilterFlags, sizeof(DWORD))) { ErrorTrace(NULL, "Invalid parameter: pdwSupportedFilterFlags\n"); TraceFunctLeave(); return(E_INVALIDARG); }
hr = HrGetAQInstance(wszInstance, TRUE, &pIAdvQueueAdmin, &paqrpc); if (FAILED(hr) && (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) != hr)) return hr;
//
// If we cannot get the instance, then try again only requesting
// read-only access
//
if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr) { fHasWriteAccess = FALSE; hr = HrGetAQInstance(wszInstance, FALSE, &pIAdvQueueAdmin, &paqrpc); }
if (SUCCEEDED(hr)) { hr = pIAdvQueueAdmin->QuerySupportedActions(pqlQueueLinkId, pdwSupportedActions, pdwSupportedFilterFlags);
paqrpc->ShutdownUnlock(); pIAdvQueueAdmin->Release(); paqrpc->Release();
//
// If the caller does not have write access, we need to
// censor the supported actions
//
if (!fHasWriteAccess) *pdwSupportedActions = 0; }
TraceFunctLeave(); return hr; }
//---[ MIDL_user_allocate ]----------------------------------------------------
//
//
// Description:
// MIDL memory allocation
// Parameters:
// size : Memory size requested.
// Returns:
// Pointer to the allocated memory block.
// History:
// 6/5/99 - MikeSwa Created (taken from smtpapi rcputil.c)
//
//-----------------------------------------------------------------------------
PVOID MIDL_user_allocate(IN size_t size) { PVOID pvBlob = NULL;
pvBlob = LocalAlloc( LPTR, size);
return(pvBlob);
}
//---[ MIDL_user_free ]--------------------------------------------------------
//
//
// Description:
// MIDL memory free .
// Parameters:
// IN pvBlob Pointer to a memory block that is freed.
// Returns:
// -
// History:
// 6/5/99 - MikeSwa Created (from smtpapi rcputil.c)
//
//-----------------------------------------------------------------------------
VOID MIDL_user_free(IN PVOID pvBlob) { LocalFree(pvBlob); }
|