469,632 Members | 1,681 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,632 developers. It's quick & easy.

Remote call to COM impersonating another user

I need to call a COM object from a remote machine using C#. I also need to
pass on a different userID and password to the call. Has anyone done this?
I've used Java to do this using JIntegra, but the application I'm using
requires .NET.

Any advice?
Jan 7 '08 #1
11 3567
Well, you are more than likely going to have to call through DCOM/COM+.
Assuming you have it set up correctly on the other machine, and you have an
interface definition for the COM object you want to call, you can call the
GetTypeFromProgID (or GetTypeFromCLSID), using the overload which will take
a remote machine name. You would then create an instance of that type
through a call to CreateInstance on the Activator class, and cast to your
interface type.

Mind you, the semantics of making a remote call are different than just
making a regular COM call (activation contexts, instancing, and the like).

Do you already have the object set up for remote calls?

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com...
>I need to call a COM object from a remote machine using C#. I also need to
pass on a different userID and password to the call. Has anyone done this?
I've used Java to do this using JIntegra, but the application I'm using
requires .NET.

Any advice?

Jan 7 '08 #2
It's set up for remote calls - I am able to make these calls remotely using
JIntegra. I guess what I need is to duplicate what JIntegra does. I get
authentication errors which leads me to believe that I need the mechanism
that sets up the call with credentials - in this case userID, password.


"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.comwrote in
message news:%2***************@TK2MSFTNGP03.phx.gbl...
Well, you are more than likely going to have to call through DCOM/COM+.
Assuming you have it set up correctly on the other machine, and you have
an interface definition for the COM object you want to call, you can call
the GetTypeFromProgID (or GetTypeFromCLSID), using the overload which will
take a remote machine name. You would then create an instance of that
type through a call to CreateInstance on the Activator class, and cast to
your interface type.

Mind you, the semantics of making a remote call are different than just
making a regular COM call (activation contexts, instancing, and the like).

Do you already have the object set up for remote calls?

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com...
>>I need to call a COM object from a remote machine using C#. I also need to
pass on a different userID and password to the call. Has anyone done this?
I've used Java to do this using JIntegra, but the application I'm using
requires .NET.

Any advice?


Jan 7 '08 #3
Well, you can always impersonate that caller on the client thread, and
then call the CoImpersonateClient API function through the P/Invoke layer
(make sure to call CoRevertToSelf).

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com...
It's set up for remote calls - I am able to make these calls remotely
using JIntegra. I guess what I need is to duplicate what JIntegra does. I
get authentication errors which leads me to believe that I need the
mechanism that sets up the call with credentials - in this case userID,
password.


"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.comwrote
in message news:%2***************@TK2MSFTNGP03.phx.gbl...
> Well, you are more than likely going to have to call through
DCOM/COM+. Assuming you have it set up correctly on the other machine,
and you have an interface definition for the COM object you want to call,
you can call the GetTypeFromProgID (or GetTypeFromCLSID), using the
overload which will take a remote machine name. You would then create an
instance of that type through a call to CreateInstance on the Activator
class, and cast to your interface type.

Mind you, the semantics of making a remote call are different than
just making a regular COM call (activation contexts, instancing, and the
like).

Do you already have the object set up for remote calls?

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com...
>>>I need to call a COM object from a remote machine using C#. I also need
to pass on a different userID and password to the call. Has anyone done
this? I've used Java to do this using JIntegra, but the application I'm
using requires .NET.

Any advice?



Jan 7 '08 #4
My situation is I'm the C# client. I don't have access to the server code. I
know the credentials I need to access the COM server. When my client calls
the COM object it gets rejected. When I use JIntegra, I set the credentials
before I make the call, and the COM server is happy. CoImpersonateClient
seems to be something the server calls.

Since JIntegra can do it, there's obviously a way. I just don't know what
calls they make to do it, and they're not telling.

"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.comwrote in
message news:eQ**************@TK2MSFTNGP06.phx.gbl...
Well, you can always impersonate that caller on the client thread, and
then call the CoImpersonateClient API function through the P/Invoke layer
(make sure to call CoRevertToSelf).

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com...
>It's set up for remote calls - I am able to make these calls remotely
using JIntegra. I guess what I need is to duplicate what JIntegra does. I
get authentication errors which leads me to believe that I need the
mechanism that sets up the call with credentials - in this case userID,
password.


"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.comwrote
in message news:%2***************@TK2MSFTNGP03.phx.gbl...
>> Well, you are more than likely going to have to call through
DCOM/COM+. Assuming you have it set up correctly on the other machine,
and you have an interface definition for the COM object you want to
call, you can call the GetTypeFromProgID (or GetTypeFromCLSID), using
the overload which will take a remote machine name. You would then
create an instance of that type through a call to CreateInstance on the
Activator class, and cast to your interface type.

Mind you, the semantics of making a remote call are different than
just making a regular COM call (activation contexts, instancing, and the
like).

Do you already have the object set up for remote calls?

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com.. .
I need to call a COM object from a remote machine using C#. I also need
to pass on a different userID and password to the call. Has anyone done
this? I've used Java to do this using JIntegra, but the application I'm
using requires .NET.

Any advice?



Jan 7 '08 #5
JCav,

You are right. Willy actually posted the correct answer just below.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"JCav" <jc********@cinci.rr.comwrote in message
news:47***********************@roadrunner.com...
My situation is I'm the C# client. I don't have access to the server code.
I know the credentials I need to access the COM server. When my client
calls the COM object it gets rejected. When I use JIntegra, I set the
credentials before I make the call, and the COM server is happy.
CoImpersonateClient seems to be something the server calls.

Since JIntegra can do it, there's obviously a way. I just don't know what
calls they make to do it, and they're not telling.

"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.comwrote
in message news:eQ**************@TK2MSFTNGP06.phx.gbl...
> Well, you can always impersonate that caller on the client thread, and
then call the CoImpersonateClient API function through the P/Invoke layer
(make sure to call CoRevertToSelf).

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com...
>>It's set up for remote calls - I am able to make these calls remotely
using JIntegra. I guess what I need is to duplicate what JIntegra does.
I get authentication errors which leads me to believe that I need the
mechanism that sets up the call with credentials - in this case userID,
password.


"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.comwrote
in message news:%2***************@TK2MSFTNGP03.phx.gbl...
Well, you are more than likely going to have to call through
DCOM/COM+. Assuming you have it set up correctly on the other machine,
and you have an interface definition for the COM object you want to
call, you can call the GetTypeFromProgID (or GetTypeFromCLSID), using
the overload which will take a remote machine name. You would then
create an instance of that type through a call to CreateInstance on the
Activator class, and cast to your interface type.

Mind you, the semantics of making a remote call are different than
just making a regular COM call (activation contexts, instancing, and
the like).

Do you already have the object set up for remote calls?

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com. ..
>I need to call a COM object from a remote machine using C#. I also need
>to pass on a different userID and password to the call. Has anyone done
>this? I've used Java to do this using JIntegra, but the application I'm
>using requires .NET.
>
Any advice?
>




Jan 7 '08 #6
"JCav" <jc********@cinci.rr.comwrote in message
news:47***********************@roadrunner.com...
My situation is I'm the C# client. I don't have access to the server code.
I know the credentials I need to access the COM server. When my client
calls the COM object it gets rejected. When I use JIntegra, I set the
credentials before I make the call, and the COM server is happy.
CoImpersonateClient seems to be something the server calls.

Since JIntegra can do it, there's obviously a way. I just don't know what
calls they make to do it, and they're not telling.
I told you what you need to do, see my other reply.

Willy.

Jan 7 '08 #7
"JCav" <jc********@cinci.rr.comwrote in message
news:47***********************@roadrunner.com...
I'm new to this, so bear with me. I seem to be missing something.

When I call LogonUser, it fails, I think because the domain I need to log
into is not available from the machine I run this from. When I use
the local domain it works fine - I become the other user when I
impersonate him. This is how far I got before the original post. Is there
a call
that sends this information to the server and tells it to do this? As I
said, this works with whatever JIntegra does it.
You don't have to send this information to the server, it's the role of COM
to authenticate the client and pass the security context to the server.
When you call CoInitializeSecurity, specifying DynamicCloaking (or
StaticCloacking) very early in the process, COM will automatically pass the
impersonation token of the client to the server, the server will use this
token when impersonating (the server needs to call CoImpersonateClient for
this).
What you need to take care of is that the token passed is an impersonating
token, so be carefull when calling LogonUser, the token sent must be an
impersonation token not a direct token.
That means that you'll have to specify a "batch" or "interactive" logon type
when calling LogonUser, before calling Impersonate. Another option is to use
a "network" logon type and call "DuplicateToken" before using the duplicated
token in the Impersonate call.


Willy.

Jan 8 '08 #8
These are the calls I'm using. LogonUser is failing with a 1326 - invalid
userID or password, even though these work when I log onto the machine. So I
never get far enough to make the call to the COM object.
int retxxx = CoInitializeSecurity(IntPtr.Zero, -1, IntPtr.Zero, IntPtr.Zero,
RpcAuthnLevel.Connect, RpcImpLevel.Impersonate, IntPtr.Zero,
(int)EoAuthnCap.DynamicCloaking, IntPtr.Zero);

const int LOGON32_PROVIDER_DEFAULT = 0;

const int LOGON32_LOGON_INTERACTIVE = 2;

const int LOGON32_LOGON_NETWORK = 3;

IntPtr tokenHandle = new IntPtr(0);

bool returnValue = LogonUser(xxx", "yyy", "zzz",LOGON32_LOGON_NETWORK,
LOGON32_PROVIDER_DEFAULT, ref tokenHandle);

"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:ub****************@TK2MSFTNGP06.phx.gbl...
"JCav" <jc********@cinci.rr.comwrote in message
news:47***********************@roadrunner.com...
>I'm new to this, so bear with me. I seem to be missing something.

When I call LogonUser, it fails, I think because the domain I need to log
into is not available from the machine I run this from. When I use
the local domain it works fine - I become the other user when I
impersonate him. This is how far I got before the original post. Is there
a call
that sends this information to the server and tells it to do this? As I
said, this works with whatever JIntegra does it.

You don't have to send this information to the server, it's the role of
COM to authenticate the client and pass the security context to the
server.
When you call CoInitializeSecurity, specifying DynamicCloaking (or
StaticCloacking) very early in the process, COM will automatically pass
the impersonation token of the client to the server, the server will use
this token when impersonating (the server needs to call
CoImpersonateClient for this).
What you need to take care of is that the token passed is an impersonating
token, so be carefull when calling LogonUser, the token sent must be an
impersonation token not a direct token.
That means that you'll have to specify a "batch" or "interactive" logon
type when calling LogonUser, before calling Impersonate. Another option is
to use a "network" logon type and call "DuplicateToken" before using the
duplicated token in the Impersonate call.


Willy.

Jan 8 '08 #9
"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com...
These are the calls I'm using. LogonUser is failing with a 1326 - invalid
userID or password, even though these work when I log onto the machine. So
I never get far enough to make the call to the COM object.
int retxxx = CoInitializeSecurity(IntPtr.Zero, -1, IntPtr.Zero,
IntPtr.Zero, RpcAuthnLevel.Connect, RpcImpLevel.Impersonate, IntPtr.Zero,
(int)EoAuthnCap.DynamicCloaking, IntPtr.Zero);

const int LOGON32_PROVIDER_DEFAULT = 0;

const int LOGON32_LOGON_INTERACTIVE = 2;

const int LOGON32_LOGON_NETWORK = 3;

IntPtr tokenHandle = new IntPtr(0);

bool returnValue = LogonUser(xxx", "yyy", "zzz",LOGON32_LOGON_NETWORK,
LOGON32_PROVIDER_DEFAULT, ref tokenHandle);
And you function declaration looks like:

[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool LogonUser(
string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr hToken);

bool result = LogonUser(name, domain, passwd,
LOGON32_LOGON_INTERACTIVE ,
LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
if (result == false) // If failed
{
}
else // success
{

Note that you should use LOGON32_LOGON_INTERACTIVE or LOGON32_LOGON_BATCH
(value 4) as logon type, other types will not return a token that can be
used to impersonate unless you are running in the context of an
administrator (or an account with "SeImpersonatePrivileges" enabled) .
Willy.

Jan 8 '08 #10
I call LogonUser just the way you specified and I'm still getting the 1326:

int ret = CoInitializeSecurity(IntPtr.Zero,-1,IntPtr.Zero,IntPtr.Zero,
RpcAuthnLevel.Connect,RpcImpLevel.Impersonate, IntPtr.Zero,
(int)EoAuthnCap.DynamicCloaking, IntPtr.Zero);

ret is zero ...
bool returnValue = LogonUser("UID", "Domain", "password",
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref tokenHandle);

returns false with a code of 1326

I can connect to the machine in question using these values and mstsc.exe.
The domain I use to log into my machine is different from the domain I use
above. Is this an issue? Is there some kind of administrative flag keeping
me from doing this? Am I calling CoInitializeSecurity with the wrong values?
I'm using the definitions you sent in an earlier post.

"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:OB**************@TK2MSFTNGP02.phx.gbl...
"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com...
>These are the calls I'm using. LogonUser is failing with a 1326 - invalid
userID or password, even though these work when I log onto the machine.
So I never get far enough to make the call to the COM object.
int retxxx = CoInitializeSecurity(IntPtr.Zero, -1, IntPtr.Zero,
IntPtr.Zero, RpcAuthnLevel.Connect, RpcImpLevel.Impersonate, IntPtr.Zero,
(int)EoAuthnCap.DynamicCloaking, IntPtr.Zero);

const int LOGON32_PROVIDER_DEFAULT = 0;

const int LOGON32_LOGON_INTERACTIVE = 2;

const int LOGON32_LOGON_NETWORK = 3;

IntPtr tokenHandle = new IntPtr(0);

bool returnValue = LogonUser(xxx", "yyy", "zzz",LOGON32_LOGON_NETWORK,
LOGON32_PROVIDER_DEFAULT, ref tokenHandle);

And you function declaration looks like:

[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool LogonUser(
string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr hToken);

bool result = LogonUser(name, domain, passwd,
LOGON32_LOGON_INTERACTIVE ,
LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
if (result == false) // If failed
{
}
else // success
{

Note that you should use LOGON32_LOGON_INTERACTIVE or LOGON32_LOGON_BATCH
(value 4) as logon type, other types will not return a token that can be
used to impersonate unless you are running in the context of an
administrator (or an account with "SeImpersonatePrivileges" enabled) .
Willy.

Jan 10 '08 #11
"JCav" <jc********@cinci.rr.comwrote in message
news:47**********************@roadrunner.com...
>I call LogonUser just the way you specified and I'm still getting the 1326:

int ret = CoInitializeSecurity(IntPtr.Zero,-1,IntPtr.Zero,IntPtr.Zero,
RpcAuthnLevel.Connect,RpcImpLevel.Impersonate, IntPtr.Zero,
(int)EoAuthnCap.DynamicCloaking, IntPtr.Zero);

ret is zero ...
bool returnValue = LogonUser("UID", "Domain", "password",
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref tokenHandle);

returns false with a code of 1326

I can connect to the machine in question using these values and mstsc.exe.
The domain I use to log into my machine is different from the domain I use
above. Is this an issue? Is there some kind of administrative flag keeping
me from doing this? Am I calling CoInitializeSecurity with the wrong
values? I'm using the definitions you sent in an earlier post.
You can't use LogonUser to get a token from a non trusted domain, if the
callers domain is trusted by the called domain there shouldn't be a problem.
When there is no domain trust, the caller cannot locate the domain and the
call will fail.
CoInitializeSecurity has nothing to do with this. What happens when you call
LogonUser specifying the credentials of a local account?, or the
credentials of an account on a remote system, hereby specifying the machine
name instead of the domain name(same or other domain).

Willy.

Jan 11 '08 #12

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by Jon L. Lovesky | last post: by
3 posts views Thread by Billy Bob | last post: by
2 posts views Thread by =?Utf-8?B?RGFuaWVsIENvcnLDqmE=?= | last post: by
3 posts views Thread by Looch | last post: by
reply views Thread by gheharukoh7 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.