DCOM and ConnectionPoint
-
Hi, I have an ATL component. My Client is a standard VB application. The component fires events. Events are directly handled by VB Client. This works fine as long as the component is a local server. I want to use this component from a remote machine.. But when I make it a remote server, I get the error, "PERMISSION DENIED" I tried all possible combinations in DcomCnfg Dialog. I specified the permissions (in Security Tab). I tried "Interactive & Launching User" Identities but it gives the same error. But when I specify the Username & password of the client machine, it creates an instance of server on Host machine... ...But it hangs after that.. Can anyone help me out .... Is it that one cannot use Connection points in Dcom ...:confused: Please some body reply to this message.... Firoz.
-
Hi, I have an ATL component. My Client is a standard VB application. The component fires events. Events are directly handled by VB Client. This works fine as long as the component is a local server. I want to use this component from a remote machine.. But when I make it a remote server, I get the error, "PERMISSION DENIED" I tried all possible combinations in DcomCnfg Dialog. I specified the permissions (in Security Tab). I tried "Interactive & Launching User" Identities but it gives the same error. But when I specify the Username & password of the client machine, it creates an instance of server on Host machine... ...But it hangs after that.. Can anyone help me out .... Is it that one cannot use Connection points in Dcom ...:confused: Please some body reply to this message.... Firoz.
With Connection Points you have too have the right Security Setting on both machines. Essentially it is a two way duplex communication system Machine A must have right to Machine B and Machine B must have rights to Machine A Check you security settings on both Machines
-
Hi, I have an ATL component. My Client is a standard VB application. The component fires events. Events are directly handled by VB Client. This works fine as long as the component is a local server. I want to use this component from a remote machine.. But when I make it a remote server, I get the error, "PERMISSION DENIED" I tried all possible combinations in DcomCnfg Dialog. I specified the permissions (in Security Tab). I tried "Interactive & Launching User" Identities but it gives the same error. But when I specify the Username & password of the client machine, it creates an instance of server on Host machine... ...But it hangs after that.. Can anyone help me out .... Is it that one cannot use Connection points in Dcom ...:confused: Please some body reply to this message.... Firoz.
-
Hi, I have an ATL component. My Client is a standard VB application. The component fires events. Events are directly handled by VB Client. This works fine as long as the component is a local server. I want to use this component from a remote machine.. But when I make it a remote server, I get the error, "PERMISSION DENIED" I tried all possible combinations in DcomCnfg Dialog. I specified the permissions (in Security Tab). I tried "Interactive & Launching User" Identities but it gives the same error. But when I specify the Username & password of the client machine, it creates an instance of server on Host machine... ...But it hangs after that.. Can anyone help me out .... Is it that one cannot use Connection points in Dcom ...:confused: Please some body reply to this message.... Firoz.
The first thing that should be done is that COM security should be turned off in the client. Of course, if your client is also acting as a server or is a DLL being loaded by another application, you might not have this option.
hResult = CoInitializeSecurity (NULL, -1, NULL, NULL, RPC\_C\_AUTHN\_LEVEL\_NONE, RPC\_C\_IMP\_LEVEL\_IDENTIFY, NULL, EOAC\_NONE, NULL);
This needs to be done after you call CoInitialize or CoInitializeEx. Next, you need a routine in your server such as the following.
//-----------------------------------------------------------------------------
//
// @func Remove all security
//
// @parm IUnknown * | pUnk | Interface to remove security
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------inline HRESULT DtRemoveSecurity (IUnknown *pUnk)
{
HRESULT hResult;// // Get the real IUnknown interface // CComPtr <IUnknown> pRealUnk; hResult = pUnk ->QueryInterface (IID\_IUnknown, (void \*\*) &pRealUnk); if (SUCCEEDED (hResult) && pRealUnk != pUnk) { hResult = CoSetProxyBlanket (pRealUnk, RPC\_C\_AUTHN\_NONE, RPC\_C\_AUTHZ\_NONE, 0, RPC\_C\_AUTHN\_LEVEL\_NONE, RPC\_C\_IMP\_LEVEL\_ANONYMOUS, 0, EOAC\_NONE); } // // Set the original unknown // hResult = CoSetProxyBlanket (pUnk, RPC\_C\_AUTHN\_NONE, RPC\_C\_AUTHZ\_NONE, 0, RPC\_C\_AUTHN\_LEVEL\_NONE, RPC\_C\_IMP\_LEVEL\_ANONYMOUS, 0, EOAC\_NONE); return hResult;
}
Next thing you will need to do is modify your XXX::Advise method for your connection point. You might have to subclass the ATL routine do to this. Inside the XXX::Advise routine, there is usally a point where the interface is queried for the actual interface needed. The code should be modified.
CComPtr <IUnknown> p; HRESULT hResult = pUnkSink ->QueryInterface (\*\_piid, (void \*\*) &p); if (FAILED (hResult)) { DtRemoveSecurity (pUnkSink); hResult = pUnkSink ->QueryInterface (\*\_piid, (void \*\*) &p); if (FAILED (hResult)) return CONNECT\_E\_CANNOTCONNECT; }
This code test to see if you can query the interface. If it fails then security is removed and then another attempt is made. At this stage it is important that you don't blindly remove security since that causes problems with connections on the local machine. Now, if you are using a GIT based connection point, then after the interface is retrieved from the GIT, you will need to invoke DtRemoveSecurity on the retrieved interface. This can be
-
The first thing that should be done is that COM security should be turned off in the client. Of course, if your client is also acting as a server or is a DLL being loaded by another application, you might not have this option.
hResult = CoInitializeSecurity (NULL, -1, NULL, NULL, RPC\_C\_AUTHN\_LEVEL\_NONE, RPC\_C\_IMP\_LEVEL\_IDENTIFY, NULL, EOAC\_NONE, NULL);
This needs to be done after you call CoInitialize or CoInitializeEx. Next, you need a routine in your server such as the following.
//-----------------------------------------------------------------------------
//
// @func Remove all security
//
// @parm IUnknown * | pUnk | Interface to remove security
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------inline HRESULT DtRemoveSecurity (IUnknown *pUnk)
{
HRESULT hResult;// // Get the real IUnknown interface // CComPtr <IUnknown> pRealUnk; hResult = pUnk ->QueryInterface (IID\_IUnknown, (void \*\*) &pRealUnk); if (SUCCEEDED (hResult) && pRealUnk != pUnk) { hResult = CoSetProxyBlanket (pRealUnk, RPC\_C\_AUTHN\_NONE, RPC\_C\_AUTHZ\_NONE, 0, RPC\_C\_AUTHN\_LEVEL\_NONE, RPC\_C\_IMP\_LEVEL\_ANONYMOUS, 0, EOAC\_NONE); } // // Set the original unknown // hResult = CoSetProxyBlanket (pUnk, RPC\_C\_AUTHN\_NONE, RPC\_C\_AUTHZ\_NONE, 0, RPC\_C\_AUTHN\_LEVEL\_NONE, RPC\_C\_IMP\_LEVEL\_ANONYMOUS, 0, EOAC\_NONE); return hResult;
}
Next thing you will need to do is modify your XXX::Advise method for your connection point. You might have to subclass the ATL routine do to this. Inside the XXX::Advise routine, there is usally a point where the interface is queried for the actual interface needed. The code should be modified.
CComPtr <IUnknown> p; HRESULT hResult = pUnkSink ->QueryInterface (\*\_piid, (void \*\*) &p); if (FAILED (hResult)) { DtRemoveSecurity (pUnkSink); hResult = pUnkSink ->QueryInterface (\*\_piid, (void \*\*) &p); if (FAILED (hResult)) return CONNECT\_E\_CANNOTCONNECT; }
This code test to see if you can query the interface. If it fails then security is removed and then another attempt is made. At this stage it is important that you don't blindly remove security since that causes problems with connections on the local machine. Now, if you are using a GIT based connection point, then after the interface is retrieved from the GIT, you will need to invoke DtRemoveSecurity on the retrieved interface. This can be
Excellent solution (about removing the security from the client), very clever, fits in with what Jeff Prosise says about connection points. extract from Jeff Prosise article
One of the errors that newbies often experience when they first
begin tinkering with DCOM occurs when they fail to give a remote
server process permission to perform callbacks to a client.
Suppose a client on machine A launches a COM server on machine B
and receives an interface pointer in return. Then that client
passes an interface pointer of its own to the server so the
server can perform callbacks.What's wrong with this picture? Nothing, except for the fact
that callbacks will only be permitted if the server process is
granted access permission to the client process. If the server
process is assigned the identity Mister Server, then Mister
Server must be granted access permission to the client process.
One way to grant that access permission is to have the client
process call CoInitializeSecurity. Another way is to include
Mister Server (or Everyone) in the client machine's
DefaultAccessPermission ACL.What makes this error especially difficult to diagnose is that
if connection points are involved, the failure typically doesn't
occur when the server attempts its first callback; it occurs
when the client passes its interface pointer to the server using
IConnectionPoint::Advise. Most implementations of Advise,
including ATL's, call QueryInterface on the client. But if the
server process lacks access permissions in the client process,
QueryInterface will fail. When Advise sees QueryInterface fail,
Advise will fail, too.The moral: If you're using connection points to facilitate
callbacks from remote servers and IConnectionPoint::Advise
returns E_ACCESSDENIED or E_OUTOFMEMORY, check the access
permissions on the client. Chances are the security principal
whose identity the server process has been assigned does not
have permission to call into the client process.Read the full security article at http://www.codeguru.com/activex/COMSecurity1.html and http://www.codeguru.com/activex/COMSecurity2.html
-
Excellent solution (about removing the security from the client), very clever, fits in with what Jeff Prosise says about connection points. extract from Jeff Prosise article
One of the errors that newbies often experience when they first
begin tinkering with DCOM occurs when they fail to give a remote
server process permission to perform callbacks to a client.
Suppose a client on machine A launches a COM server on machine B
and receives an interface pointer in return. Then that client
passes an interface pointer of its own to the server so the
server can perform callbacks.What's wrong with this picture? Nothing, except for the fact
that callbacks will only be permitted if the server process is
granted access permission to the client process. If the server
process is assigned the identity Mister Server, then Mister
Server must be granted access permission to the client process.
One way to grant that access permission is to have the client
process call CoInitializeSecurity. Another way is to include
Mister Server (or Everyone) in the client machine's
DefaultAccessPermission ACL.What makes this error especially difficult to diagnose is that
if connection points are involved, the failure typically doesn't
occur when the server attempts its first callback; it occurs
when the client passes its interface pointer to the server using
IConnectionPoint::Advise. Most implementations of Advise,
including ATL's, call QueryInterface on the client. But if the
server process lacks access permissions in the client process,
QueryInterface will fail. When Advise sees QueryInterface fail,
Advise will fail, too.The moral: If you're using connection points to facilitate
callbacks from remote servers and IConnectionPoint::Advise
returns E_ACCESSDENIED or E_OUTOFMEMORY, check the access
permissions on the client. Chances are the security principal
whose identity the server process has been assigned does not
have permission to call into the client process.Read the full security article at http://www.codeguru.com/activex/COMSecurity1.html and http://www.codeguru.com/activex/COMSecurity2.html
-
Thats great Tim, Thanx a lot...:-O But how can I do this with a VB client... May be, I will have to use one more component at the client side which will talk to the remote component and simply forward the events fired by the remote component to the VB Client. (But then, as you said, I cannot turn off the COM security) What can I do in this situation ?? Anyway, I will try out this... Any other suggesion about handling the remote events directly by the VB Client...?? coz...My client is in VB and I cannot change that... Thanks... Firoz
-
Hi, I have an ATL component. My Client is a standard VB application. The component fires events. Events are directly handled by VB Client. This works fine as long as the component is a local server. I want to use this component from a remote machine.. But when I make it a remote server, I get the error, "PERMISSION DENIED" I tried all possible combinations in DcomCnfg Dialog. I specified the permissions (in Security Tab). I tried "Interactive & Launching User" Identities but it gives the same error. But when I specify the Username & password of the client machine, it creates an instance of server on Host machine... ...But it hangs after that.. Can anyone help me out .... Is it that one cannot use Connection points in Dcom ...:confused: Please some body reply to this message.... Firoz.
Hi, DCOM is a Client calling a component on another computer called Server. When we talk about Events, the roles should be changed, the client will be the server and the server will be the client(Security wise). Goto this article, it might help you in this problem. http://www.codeproject.com/useritems/dcomcnfg.asp Don't forget that while configuring the client and the server, you have to give the server the required security privileges to call back the client. Regards, ShadiK. Shadi Al-Kahwaji
-
Hi, DCOM is a Client calling a component on another computer called Server. When we talk about Events, the roles should be changed, the client will be the server and the server will be the client(Security wise). Goto this article, it might help you in this problem. http://www.codeproject.com/useritems/dcomcnfg.asp Don't forget that while configuring the client and the server, you have to give the server the required security privileges to call back the client. Regards, ShadiK. Shadi Al-Kahwaji