Home All Groups Group Topic Archive Search About

Impersonating when creating a process from inside a SQL Server Assembly

Author
14 Dec 2006 7:58 PM
Keith
Hello,

This is my situation:  I'm trying to impersonate a different user when
creating a process from inside a .NET assembly on SQL Server.  Basically the
flow looks like this:

stored procedure->static C# function in Assembly->Process created in
Asembly->External Application

This works, but the external app fails because the current WindowsIdentity
is NT AUTHORITY/WINDOWS SERVICE. ; it needs to be someone else.

Now, when you are inside a .NET assembly in SQL Server, you have access to
an object called SqlContext, and it contains (among other things) a
WindowsIdentity object that is the login user who called the stored
procedure in the first place.  This is the user I want to impersonate but I
can't seem to get it to work.

In other postings I've read that you can't get this to work with a Process -
apparently the process still inherits the Principal token and but the
Impersonation token - but it DOES work with Threads.  So I thought I'd spawn
a new Thread with the correct identity and launch my process from inside.
To test the Thread idea I used:

ParameterizedThreadStart pts = new
ParameterizedThreadStart(someThreadFunction);
Thread thread = new Thread(pts);

WindowsIdentity contextID = SqlContext.WindowsIdentity;
using (WindowsImpersonationContext wip = contextID.Impersonate())
{
   thread.Start(test);
   while (thread.ThreadState == System.Threading.ThreadState.Running) { }
   wip.Undo();
}

But inside the Thread function (someThreadFunction) the
WindowsIdentity.GetCurrent() still returns NT AUTHORITY/WINDOWS SERVICE.

Am I going about this all wrong?  Is this even possible?

Any advice/suggestions appreciated!

Keith

Author
14 Dec 2006 8:30 PM
Joe Kaplan
It doesn't work this way.  Processes created with the Process class inherit
the process token, not the impersonated token.  The Process class allows you
to specify credentials in .NET 2.0, but I don't know if that would help you
in your use case, as you don't have the user's password.

You could try calling CreateProcessWithTokenW, but you'd probably also need
to call DuplicateTokenEx to convert the impersonation token in the
WindowsIdentity into a primary token.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Show quoteHide quote
"Keith" <ke***@alh.com> wrote in message
news:%23miCQt7HHHA.1044@TK2MSFTNGP02.phx.gbl...
> Hello,
>
> This is my situation:  I'm trying to impersonate a different user when
> creating a process from inside a .NET assembly on SQL Server.  Basically
> the flow looks like this:
>
> stored procedure->static C# function in Assembly->Process created in
> Asembly->External Application
>
> This works, but the external app fails because the current WindowsIdentity
> is NT AUTHORITY/WINDOWS SERVICE. ; it needs to be someone else.
>
> Now, when you are inside a .NET assembly in SQL Server, you have access to
> an object called SqlContext, and it contains (among other things) a
> WindowsIdentity object that is the login user who called the stored
> procedure in the first place.  This is the user I want to impersonate but
> I can't seem to get it to work.
>
> In other postings I've read that you can't get this to work with a
> Process - apparently the process still inherits the Principal token and
> but the Impersonation token - but it DOES work with Threads.  So I thought
> I'd spawn a new Thread with the correct identity and launch my process
> from inside. To test the Thread idea I used:
>
> ParameterizedThreadStart pts = new
> ParameterizedThreadStart(someThreadFunction);
> Thread thread = new Thread(pts);
>
> WindowsIdentity contextID = SqlContext.WindowsIdentity;
> using (WindowsImpersonationContext wip = contextID.Impersonate())
> {
>   thread.Start(test);
>   while (thread.ThreadState == System.Threading.ThreadState.Running) { }
>   wip.Undo();
> }
>
> But inside the Thread function (someThreadFunction) the
> WindowsIdentity.GetCurrent() still returns NT AUTHORITY/WINDOWS SERVICE.
>
> Am I going about this all wrong?  Is this even possible?
>
> Any advice/suggestions appreciated!
>
> Keith
>
Author
14 Dec 2006 11:38 PM
Keith
Joe,

Thanks for the reply.  I'm aware that you can't create processes this way,
but I've seen posts in this ng where they claim you can create a new Thread
that way but I can't get that to work either.  Inside the thread the current
WindowsIdentity is still WINDOWS SERVICE.

Can you confirm that creating a new Thread with an impersonated
WindowsIdentity should work?  If it does, would creating a new process
inside that thread have the correct WindowsIdentity?

k

Show quoteHide quote
"Joe Kaplan" <joseph.e.kap***@removethis.accenture.com> wrote in message
news:e26Rr67HHHA.420@TK2MSFTNGP02.phx.gbl...
> It doesn't work this way.  Processes created with the Process class
> inherit the process token, not the impersonated token.  The Process class
> allows you to specify credentials in .NET 2.0, but I don't know if that
> would help you in your use case, as you don't have the user's password.
>
> You could try calling CreateProcessWithTokenW, but you'd probably also
> need to call DuplicateTokenEx to convert the impersonation token in the
> WindowsIdentity into a primary token.
>
> Joe K.
>
> --
> Joe Kaplan-MS MVP Directory Services Programming
> Co-author of "The .NET Developer's Guide to Directory Services
> Programming"
> http://www.directoryprogramming.net
> --
> "Keith" <ke***@alh.com> wrote in message
> news:%23miCQt7HHHA.1044@TK2MSFTNGP02.phx.gbl...
>> Hello,
>>
>> This is my situation:  I'm trying to impersonate a different user when
>> creating a process from inside a .NET assembly on SQL Server.  Basically
>> the flow looks like this:
>>
>> stored procedure->static C# function in Assembly->Process created in
>> Asembly->External Application
>>
>> This works, but the external app fails because the current
>> WindowsIdentity is NT AUTHORITY/WINDOWS SERVICE. ; it needs to be someone
>> else.
>>
>> Now, when you are inside a .NET assembly in SQL Server, you have access
>> to an object called SqlContext, and it contains (among other things) a
>> WindowsIdentity object that is the login user who called the stored
>> procedure in the first place.  This is the user I want to impersonate but
>> I can't seem to get it to work.
>>
>> In other postings I've read that you can't get this to work with a
>> Process - apparently the process still inherits the Principal token and
>> but the Impersonation token - but it DOES work with Threads.  So I
>> thought I'd spawn a new Thread with the correct identity and launch my
>> process from inside. To test the Thread idea I used:
>>
>> ParameterizedThreadStart pts = new
>> ParameterizedThreadStart(someThreadFunction);
>> Thread thread = new Thread(pts);
>>
>> WindowsIdentity contextID = SqlContext.WindowsIdentity;
>> using (WindowsImpersonationContext wip = contextID.Impersonate())
>> {
>>   thread.Start(test);
>>   while (thread.ThreadState == System.Threading.ThreadState.Running) { }
>>   wip.Undo();
>> }
>>
>> But inside the Thread function (someThreadFunction) the
>> WindowsIdentity.GetCurrent() still returns NT AUTHORITY/WINDOWS SERVICE.
>>
>> Am I going about this all wrong?  Is this even possible?
>>
>> Any advice/suggestions appreciated!
>>
>> Keith
>>
>
>
Author
15 Dec 2006 12:29 AM
Joe Kaplan
Maybe I'm just misremembering and only the ThreadPool does this
automatically now?  I'm sure Dominick or someone will correct me.

In any case, if you just spin up a thread with the Thread class, you should
be able to impersonate by passing in the WindowsIdentity in the state for
the thread and then just impersonating it manually.  It is a little
annoying, but should work.

Regardless, creating a new Process will always use the process identity
unless you start the process with explicit credentials or perhaps attempt
that pinvoke technique I mentioned.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Show quoteHide quote
"Keith" <ke***@alh.com> wrote in message
news:euNsMo9HHHA.960@TK2MSFTNGP04.phx.gbl...
> Joe,
>
> Thanks for the reply.  I'm aware that you can't create processes this way,
> but I've seen posts in this ng where they claim you can create a new
> Thread that way but I can't get that to work either.  Inside the thread
> the current WindowsIdentity is still WINDOWS SERVICE.
>
> Can you confirm that creating a new Thread with an impersonated
> WindowsIdentity should work?  If it does, would creating a new process
> inside that thread have the correct WindowsIdentity?
>
> k
>
> "Joe Kaplan" <joseph.e.kap***@removethis.accenture.com> wrote in message
> news:e26Rr67HHHA.420@TK2MSFTNGP02.phx.gbl...
>> It doesn't work this way.  Processes created with the Process class
>> inherit the process token, not the impersonated token.  The Process class
>> allows you to specify credentials in .NET 2.0, but I don't know if that
>> would help you in your use case, as you don't have the user's password.
>>
>> You could try calling CreateProcessWithTokenW, but you'd probably also
>> need to call DuplicateTokenEx to convert the impersonation token in the
>> WindowsIdentity into a primary token.
>>
>> Joe K.
>>
>> --
>> Joe Kaplan-MS MVP Directory Services Programming
>> Co-author of "The .NET Developer's Guide to Directory Services
>> Programming"
>> http://www.directoryprogramming.net
>> --
>> "Keith" <ke***@alh.com> wrote in message
>> news:%23miCQt7HHHA.1044@TK2MSFTNGP02.phx.gbl...
>>> Hello,
>>>
>>> This is my situation:  I'm trying to impersonate a different user when
>>> creating a process from inside a .NET assembly on SQL Server.  Basically
>>> the flow looks like this:
>>>
>>> stored procedure->static C# function in Assembly->Process created in
>>> Asembly->External Application
>>>
>>> This works, but the external app fails because the current
>>> WindowsIdentity is NT AUTHORITY/WINDOWS SERVICE. ; it needs to be
>>> someone else.
>>>
>>> Now, when you are inside a .NET assembly in SQL Server, you have access
>>> to an object called SqlContext, and it contains (among other things) a
>>> WindowsIdentity object that is the login user who called the stored
>>> procedure in the first place.  This is the user I want to impersonate
>>> but I can't seem to get it to work.
>>>
>>> In other postings I've read that you can't get this to work with a
>>> Process - apparently the process still inherits the Principal token and
>>> but the Impersonation token - but it DOES work with Threads.  So I
>>> thought I'd spawn a new Thread with the correct identity and launch my
>>> process from inside. To test the Thread idea I used:
>>>
>>> ParameterizedThreadStart pts = new
>>> ParameterizedThreadStart(someThreadFunction);
>>> Thread thread = new Thread(pts);
>>>
>>> WindowsIdentity contextID = SqlContext.WindowsIdentity;
>>> using (WindowsImpersonationContext wip = contextID.Impersonate())
>>> {
>>>   thread.Start(test);
>>>   while (thread.ThreadState == System.Threading.ThreadState.Running) { }
>>>   wip.Undo();
>>> }
>>>
>>> But inside the Thread function (someThreadFunction) the
>>> WindowsIdentity.GetCurrent() still returns NT AUTHORITY/WINDOWS SERVICE.
>>>
>>> Am I going about this all wrong?  Is this even possible?
>>>
>>> Any advice/suggestions appreciated!
>>>
>>> Keith
>>>
>>
>>
>
>
Author
15 Dec 2006 7:30 AM
Dominick Baier
in .NET 2.0 impersonation tokens are generally propagated to new threads
(regardless of how you create the thread).

That said - Sql Server may behave different (as does ASP.NET see http://www.leastprivilege.com/WhatIsAspnetconfig.aspx)


-----
Dominick Baier (http://www.leastprivilege.com)

Show quoteHide quote
> Maybe I'm just misremembering and only the ThreadPool does this
> automatically now?  I'm sure Dominick or someone will correct me.
>
> In any case, if you just spin up a thread with the Thread class, you
> should be able to impersonate by passing in the WindowsIdentity in the
> state for the thread and then just impersonating it manually.  It is a
> little annoying, but should work.
>
> Regardless, creating a new Process will always use the process
> identity unless you start the process with explicit credentials or
> perhaps attempt that pinvoke technique I mentioned.
>
> Joe K.
>
Author
15 Dec 2006 7:31 AM
Dominick Baier
You may also have a look at System.Threading.ExecutionContext...


But be aware that some things are just not allowed/supported in SQL Server...
-----
Dominick Baier (http://www.leastprivilege.com)

Show quoteHide quote
> Maybe I'm just misremembering and only the ThreadPool does this
> automatically now?  I'm sure Dominick or someone will correct me.
>
> In any case, if you just spin up a thread with the Thread class, you
> should be able to impersonate by passing in the WindowsIdentity in the
> state for the thread and then just impersonating it manually.  It is a
> little annoying, but should work.
>
> Regardless, creating a new Process will always use the process
> identity unless you start the process with explicit credentials or
> perhaps attempt that pinvoke technique I mentioned.
>
> Joe K.
>
Author
15 Dec 2006 1:28 AM
Keith
Joe,

I found this article and if you substitute SQL Server for IIS/ASP.NET it
gets pretty close:

http://support.microsoft.com/default.aspx?scid=kb;EN-US;889251

Sadly, I can't get this to work either; the DuplicateTokenEx always fails if
I user the SqContext.WindowsIdentity.Token of the login user.  I added the
required user rights (Replace a process level token) at the local and domain
level, but DuplicateTokenEx still returns 0 (as does LastError).  It does
work if I use CurrentUser() which is WINDOWS SERVICE.

Any ideas how I might be able to find out why the DuplicateTokenEx is
failing?

Keith

Show quoteHide quote
"Keith" <ke***@alh.com> wrote in message
news:euNsMo9HHHA.960@TK2MSFTNGP04.phx.gbl...
> Joe,
>
> Thanks for the reply.  I'm aware that you can't create processes this way,
> but I've seen posts in this ng where they claim you can create a new
> Thread that way but I can't get that to work either.  Inside the thread
> the current WindowsIdentity is still WINDOWS SERVICE.
>
> Can you confirm that creating a new Thread with an impersonated
> WindowsIdentity should work?  If it does, would creating a new process
> inside that thread have the correct WindowsIdentity?
>
> k
>
> "Joe Kaplan" <joseph.e.kap***@removethis.accenture.com> wrote in message
> news:e26Rr67HHHA.420@TK2MSFTNGP02.phx.gbl...
>> It doesn't work this way.  Processes created with the Process class
>> inherit the process token, not the impersonated token.  The Process class
>> allows you to specify credentials in .NET 2.0, but I don't know if that
>> would help you in your use case, as you don't have the user's password.
>>
>> You could try calling CreateProcessWithTokenW, but you'd probably also
>> need to call DuplicateTokenEx to convert the impersonation token in the
>> WindowsIdentity into a primary token.
>>
>> Joe K.
>>
>> --
>> Joe Kaplan-MS MVP Directory Services Programming
>> Co-author of "The .NET Developer's Guide to Directory Services
>> Programming"
>> http://www.directoryprogramming.net
>> --
>> "Keith" <ke***@alh.com> wrote in message
>> news:%23miCQt7HHHA.1044@TK2MSFTNGP02.phx.gbl...
>>> Hello,
>>>
>>> This is my situation:  I'm trying to impersonate a different user when
>>> creating a process from inside a .NET assembly on SQL Server.  Basically
>>> the flow looks like this:
>>>
>>> stored procedure->static C# function in Assembly->Process created in
>>> Asembly->External Application
>>>
>>> This works, but the external app fails because the current
>>> WindowsIdentity is NT AUTHORITY/WINDOWS SERVICE. ; it needs to be
>>> someone else.
>>>
>>> Now, when you are inside a .NET assembly in SQL Server, you have access
>>> to an object called SqlContext, and it contains (among other things) a
>>> WindowsIdentity object that is the login user who called the stored
>>> procedure in the first place.  This is the user I want to impersonate
>>> but I can't seem to get it to work.
>>>
>>> In other postings I've read that you can't get this to work with a
>>> Process - apparently the process still inherits the Principal token and
>>> but the Impersonation token - but it DOES work with Threads.  So I
>>> thought I'd spawn a new Thread with the correct identity and launch my
>>> process from inside. To test the Thread idea I used:
>>>
>>> ParameterizedThreadStart pts = new
>>> ParameterizedThreadStart(someThreadFunction);
>>> Thread thread = new Thread(pts);
>>>
>>> WindowsIdentity contextID = SqlContext.WindowsIdentity;
>>> using (WindowsImpersonationContext wip = contextID.Impersonate())
>>> {
>>>   thread.Start(test);
>>>   while (thread.ThreadState == System.Threading.ThreadState.Running) { }
>>>   wip.Undo();
>>> }
>>>
>>> But inside the Thread function (someThreadFunction) the
>>> WindowsIdentity.GetCurrent() still returns NT AUTHORITY/WINDOWS SERVICE.
>>>
>>> Am I going about this all wrong?  Is this even possible?
>>>
>>> Any advice/suggestions appreciated!
>>>
>>> Keith
>>>
>>
>>
>
>
Author
15 Dec 2006 2:37 AM
Joe Kaplan
I don't really have any idea on this one, but GetLastError should work.  I'd
suggest trying to use the Marshal.GetLastWin32Error and make sure you call
that right after you call DuplicateTokenEx to ensure that nothing clears
that state.  Maybe that will help.

This might be a question you want to try out in the PlatformSDK.Security
newsgroup too.

Good luck!

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Show quoteHide quote
"Keith" <ke***@alh.com> wrote in message
news:%23x%23yVl%23HHHA.3268@TK2MSFTNGP04.phx.gbl...
> Joe,
>
> I found this article and if you substitute SQL Server for IIS/ASP.NET it
> gets pretty close:
>
> http://support.microsoft.com/default.aspx?scid=kb;EN-US;889251
>
> Sadly, I can't get this to work either; the DuplicateTokenEx always fails
> if I user the SqContext.WindowsIdentity.Token of the login user.  I added
> the required user rights (Replace a process level token) at the local and
> domain level, but DuplicateTokenEx still returns 0 (as does LastError).
> It does work if I use CurrentUser() which is WINDOWS SERVICE.
>
> Any ideas how I might be able to find out why the DuplicateTokenEx is
> failing?
>
> Keith
>
> "Keith" <ke***@alh.com> wrote in message
> news:euNsMo9HHHA.960@TK2MSFTNGP04.phx.gbl...
>> Joe,
>>
>> Thanks for the reply.  I'm aware that you can't create processes this
>> way, but I've seen posts in this ng where they claim you can create a new
>> Thread that way but I can't get that to work either.  Inside the thread
>> the current WindowsIdentity is still WINDOWS SERVICE.
>>
>> Can you confirm that creating a new Thread with an impersonated
>> WindowsIdentity should work?  If it does, would creating a new process
>> inside that thread have the correct WindowsIdentity?
>>
>> k
>>
>> "Joe Kaplan" <joseph.e.kap***@removethis.accenture.com> wrote in message
>> news:e26Rr67HHHA.420@TK2MSFTNGP02.phx.gbl...
>>> It doesn't work this way.  Processes created with the Process class
>>> inherit the process token, not the impersonated token.  The Process
>>> class allows you to specify credentials in .NET 2.0, but I don't know if
>>> that would help you in your use case, as you don't have the user's
>>> password.
>>>
>>> You could try calling CreateProcessWithTokenW, but you'd probably also
>>> need to call DuplicateTokenEx to convert the impersonation token in the
>>> WindowsIdentity into a primary token.
>>>
>>> Joe K.
>>>
>>> --
>>> Joe Kaplan-MS MVP Directory Services Programming
>>> Co-author of "The .NET Developer's Guide to Directory Services
>>> Programming"
>>> http://www.directoryprogramming.net
>>> --
>>> "Keith" <ke***@alh.com> wrote in message
>>> news:%23miCQt7HHHA.1044@TK2MSFTNGP02.phx.gbl...
>>>> Hello,
>>>>
>>>> This is my situation:  I'm trying to impersonate a different user when
>>>> creating a process from inside a .NET assembly on SQL Server.
>>>> Basically the flow looks like this:
>>>>
>>>> stored procedure->static C# function in Assembly->Process created in
>>>> Asembly->External Application
>>>>
>>>> This works, but the external app fails because the current
>>>> WindowsIdentity is NT AUTHORITY/WINDOWS SERVICE. ; it needs to be
>>>> someone else.
>>>>
>>>> Now, when you are inside a .NET assembly in SQL Server, you have access
>>>> to an object called SqlContext, and it contains (among other things) a
>>>> WindowsIdentity object that is the login user who called the stored
>>>> procedure in the first place.  This is the user I want to impersonate
>>>> but I can't seem to get it to work.
>>>>
>>>> In other postings I've read that you can't get this to work with a
>>>> Process - apparently the process still inherits the Principal token and
>>>> but the Impersonation token - but it DOES work with Threads.  So I
>>>> thought I'd spawn a new Thread with the correct identity and launch my
>>>> process from inside. To test the Thread idea I used:
>>>>
>>>> ParameterizedThreadStart pts = new
>>>> ParameterizedThreadStart(someThreadFunction);
>>>> Thread thread = new Thread(pts);
>>>>
>>>> WindowsIdentity contextID = SqlContext.WindowsIdentity;
>>>> using (WindowsImpersonationContext wip = contextID.Impersonate())
>>>> {
>>>>   thread.Start(test);
>>>>   while (thread.ThreadState == System.Threading.ThreadState.Running)
>>>> { }
>>>>   wip.Undo();
>>>> }
>>>>
>>>> But inside the Thread function (someThreadFunction) the
>>>> WindowsIdentity.GetCurrent() still returns NT AUTHORITY/WINDOWS
>>>> SERVICE.
>>>>
>>>> Am I going about this all wrong?  Is this even possible?
>>>>
>>>> Any advice/suggestions appreciated!
>>>>
>>>> Keith
>>>>
>>>
>>>
>>
>>
>
>
Author
15 Dec 2006 6:12 PM
Andy
Don't know much about security, but just a thought if you are
experiencing failures for many examples that should have worked...

If you are using Active Directory, do you have Kerbros security turned
on (it is shipped off by default)?   Will turning it on make a
difference as to whether the primary or the impersonation token is
passed?  I understand Kerbros will allow an impersonation token to make
multiple hops while windows security does not.

Andy