sampel code for a service broker required
-
Wednesday, May 09, 2012 2:58 PMHi,
in my windows service I have to call a win32 function, which I have to call from within the context / account of the current logged in user.
Early I read somewhere, that this can be done, by a so called service broker.
I can remember that such a service broker function need s to call serveral win32 API functions and at least a
function like ???ImpersonateUser?????
1. Can somebody tell me the required win32 function calls, which I need to write such a windows service broker?
2. Or even better does somebody have sample code for such a service broker?
Thanks in advance for your help.
- Edited by ThePerfectWave Wednesday, May 09, 2012 2:58 PM
- Edited by ThePerfectWave Wednesday, May 09, 2012 2:59 PM
- Edited by ThePerfectWave Wednesday, May 09, 2012 3:00 PM
- Edited by ThePerfectWave Wednesday, May 09, 2012 3:04 PM
- Edited by ThePerfectWave Wednesday, May 09, 2012 3:13 PM
All Replies
-
Wednesday, May 09, 2012 3:15 PM
You can impersonate someone simply by calling ImpersonateLoggedOnUser or SetThreadToken. Once you have finished with the impersonation then call RevertToSelf.
The tough part is how do you get the token into the service.
For an idea of how the impersonation is done:
bool DoSomethingImpersonated(HANDLE token) { if(!ImpersonateLoggedOnUser(token)) { return false; //impersonation failed } //do stuff that requires impersonation RevertToSelf(); return true; }That is it.
You can create the impersonation token by calling DuplicateToken if needed, but ImpersonateLoggedOnUser should be able use a primary token without issue if you open it up with the duplicate access right.
This is a signature
Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.
Do you want Visual Studio 11 Express to be freely installable on Windows 7 and able to write regular C++ applications? Please vote for this.- Edited by Crescens2k Wednesday, May 09, 2012 3:16 PM
- Proposed As Answer by Jesse JiangMicrosoft Contingent Staff, Moderator Thursday, May 10, 2012 6:16 AM
-
Thursday, May 10, 2012 8:00 AMThanks for that fast helpful answer.
It's already the second part of the answer.
But the first part ( the tough one ) I also need to know:
o How can I retrieve from inside my windows service the token of the current logged on user?
It's several months ago, when somebody told my how this can be done. But unfortunately
I can't remember how this can be done. I just know it's possible.
- Edited by ThePerfectWave Thursday, May 10, 2012 8:00 AM
- Edited by ThePerfectWave Thursday, May 10, 2012 8:05 AM
- Edited by ThePerfectWave Thursday, May 10, 2012 8:06 AM
-
Thursday, May 10, 2012 8:39 AM
This is tough because there is no one easy way of doing this.
Usually, you get the service to log on as the user you want to impersonate, so this means that you will either be passing logon credentials to the service and then using LogonUser, or using SSPI. The recommendation is SSPI. You can read about both under Authentication.
This is a signature
Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.
Do you want Visual Studio 11 Express to be freely installable on Windows 7 and able to write regular C++ applications? Please vote for this. -
Thursday, May 10, 2012 11:14 AM
Thanks for that fast answer.
Meanwhile I tried the following code piece. When debugging my windows service LastError is always 0
and Succeeded also is always TRUE. But anyway the "critical code", that I run behind the impersonation
does not work. My "critical code" now should work as fine as it does in a regular application. But it
does not.
This is strange to me. Since LastError and Succeeded has been ok. And following code piece has been
executed without a failure.
==> Why does the following simple code piece not make my "critical code" to run well?
Do I realy need the complicated stuff, that is suggested by Crescens2k?
I hope not - I hope a small fix of the following code piece - will solve the problem.
BOOL Succeeded = FALSE;
DWORD LastError = 0;
DWORD ActiveConsoleSessionId = 0;
HANDLE hUserToken;
HANDLE hUserTokenDup;
ActiveConsoleSessionId = WTSGetActiveConsoleSessionId();
LastError = GetLastError();
if( 0!=LastError )
return;
Succeeded = WTSQueryUserToken( ActiveConsoleSessionId, &hUserToken );
LastError = GetLastError();
if( !Succeeded || 0!=LastError )
return;
Succeeded = DuplicateTokenEx(hUserToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary, &hUserTokenDup);
LastError = GetLastError();
if( !Succeeded || 0!=LastError )
return;
Succeeded = ImpersonateLoggedOnUser( hUserTokenDup );
LastError = GetLastError();
if( !Succeeded || 0!=LastError )
return;
// my critical code, that needs the logged on user context
....
...
..
//
RevertToSelf();- Edited by ThePerfectWave Thursday, May 10, 2012 11:15 AM
-
Thursday, May 10, 2012 9:16 PM
You should do it, authenticating to get the user token is always the best approach. To be honest, with what you want to do would require your service to be run as LocalSystem, and not many people are comfortable with allowing an unknown service to run with that kind of access. As the documentation says for WTSQueryUserToken:
Obtains the primary access token of the logged-on user specified by the session ID. To call this function successfully, the calling application must be running within the context of the LocalSystem account and have the SE_TCB_NAME privilege.
If you are running your service in the more recommended way then you just wont be able to get this to work.
Anyway, depending on what your critical code is, you may have to modify it to work with impersonation. Some functions does the access check against the process token regardless of whether the impersonation token exists. Others require you to pass in a flag to tell it that you are impersonating.
-Edit-
There is one cavet to this, if what you are doing in your service requires the LocalSystem account and SE_TCB_NAME privilege for some other operation then fine, but it is poor design and security to just require these just because you don't want to use SSPI.
Your service should only be using the absolute minimum it needs for security reasons.
This is a signature
Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.
Do you want Visual Studio 11 Express to be freely installable on Windows 7 and able to write regular C++ applications? Please vote for this.- Edited by Crescens2k Thursday, May 10, 2012 10:14 PM
- Proposed As Answer by Jesse JiangMicrosoft Contingent Staff, Moderator Friday, May 18, 2012 7:24 AM
-
Monday, May 21, 2012 12:51 PM
@Crescens2k thanks for all your help full info.
I solved the problem in my windows services in the following way: I figured out the current logged in user, herewith I created an env block and started a help process, in which I execute the critical code.
Therefore I used the following Windows API:
WTSGetActiveConsoleSessionId
WTSQueryUserToken
DuplicateTokenEx
CreateEnvironmentBlock
CreateProcessAsUser
- Marked As Answer by ThePerfectWave Monday, May 21, 2012 12:51 PM
-
Monday, May 21, 2012 2:20 PM
Out of curiosity, how are you dealing with the situation where the currently active logon session isn't the one using your service?
Because of things like Remote Desktop and fast user switching, it could be possible for the service to start what it is doing, the user switches and then the WTSGetActiveConsoleSessionId would give you the wrong session. Remember, the currently active session isn't always the one that the service has to do work for. This also doesn't help in the case where a process was run with different credentials.
By doing this, if a logon session belongs to user 1, user 1 then runs a process as user 2, then user 2 uses this service, the service will pick up the credentials for user 1. These are two reasons why, besides needing stupidly high privileges, using those WTS functions are not a good idea.
I know of a system (since it belongs to my mother and her partner) where you can pretty much guarantee that when it is started up, the person who first logs on isn't the same person who is used for the rest of the day. The usual course of events are the system starts up and one person logs on, after a while they suspend the computer, then when the other wants to use it, they come along and resume, switch users and log in (so by now two users are logged on) and then they do what they want. For a lot of the week, my sister also visits, and what then happens is that they switch accounts yet again (so that is 3 logged on) and my sister and mother watch cute videos on youtube for a while. Then finally, at the end of the day, it is shut down, forcing the log off of all users without even going back into any of the logged on accounts.
So the active console changes, the active user changes, in this case, what should your service do?
This is a signature
Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.
Do you want Visual Studio 11 Express to be freely installable on Windows 7 and able to write regular C++ applications? Please vote for this.

