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

//-----------------------------------------------------------------------------
//
//
// 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);
}