How to start process in session before user logs on?
I have a need to start a process in a session before the user logons on. On XP I used a Windows Logon Notification Package to do this. When a new session was created, Winlogon.exe in that new session called my WLNP and it was able to start the process before the user logged on. The process is used to support smart card logons for that session.
I'm trying to find out how to do something similar on Vista. I know logon notification packages are no longer supported. I know how to write a service to get session creation notification, but I don't know how to start a process in the new session before the user logs on.
Is there a function I can use to start a process in another session? If so, I could have my session tracking sevice start the process in the new session. I haven't found such a function.
I could write a credentials provider to start the process when the user hits CTRL-ALT-DEL, but I want the process started before the user takes any action because the process takes a few seconds to initialize and only starting it after the user hits CTRL-ALT-DEL would insert an undersirable delay into smart card logon.
Is there any mechanism that I can use to get code executed in a new session soon after that new session is created, before the user logs on or hits CTRL-ALT-DEL?
Thanks,
Jim Miller
Couple questions first, if you don't mind:
How do you get session creation notification?
Why do you need a process in that session for smartcard logon?
>How do you get session creation notification?
Well, I don't really. I just loop calling WTSEnumerateSessions to see if a new session has been created. It's crude, but it works. It would be better if the SERVICE_CONTROL_SESSIONCHANGE mechanism would tell you when new sessions are created, but it doesn't.
>Why do you need a process in that session for smartcard logon?
It not required, just something I'm trying to do.
I'm going to see if I can achieve my goal using a combination of OpenProcessToken, SetTokenInformation, and CreateProcessWithTokenW. I'll post here if it works.
I was curious, just in case of something "creative".
With real scenarios, it could be considered in a future release.
You'll need TCB for this, but OpenProcessToken, DuplicateTokenEx, SetTokenInformation and CreateProcessAsUser should get you going.
>You'll need TCB for this, but OpenProcessToken, DuplicateTokenEx, SetTokenInformation
> and CreateProcessAsUser should get you going.
I got it working! Here's what I did in a nutshell:
When I detect that a new session has been created I
- Use WTSEnumerateProcesses to find the process id of winlogon.exe in the new session.
- Use AdjustTokenPrivileges to give my session monitoring service SE_TCB_NAME privilage
- Call OpenProcess to get a handle to winlogon.exe process in new session
- Call OpenProcessToken to get winlogon.exe's access token.
- Call DuplicateTokenEx to make a new access token
- Call CreateProcessAsUser to start my process in the new session before user logs on.
RIght now my process runs as SYSTEM and it doesn't need to. I'm going to play around with the above a bit to see if I can get it to run as something else.
Jim
I guess that works too but it's not quite what I meant. 
Since you duplicate winlogon's token (which is already running in that session), you don't need to set the session id.
You may not even need TCB with your procedure, but probably require SYSTEM for the OpenProcess* calls anyway.
You could have duplicated your own process token, set the session id in the duped token and proceeded to step 6.
It's probably fairly equivalent.
When I Use WTSEnumerateProcesses API in my service, an error occurs. The error code is 1702 (The binding handle is invalid).
My code is like
WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, ... ...
what's wrong?
I have found that, after a reboot, the terminal services sub-system takes a while to finish initializing. You will get the 'binding handle is invalid' error until the TS sub-system is done initializing. I think there is a global event handle you can wait on to learn when TS is done initializing, but I don't remember what it is.
Anyone out there remember what it is?
This procedure is pretty inefficient in the first place. You have to wait for TS to be up, enumerate processes, find the right one, ...
The one I outlined (duplicate your own service process token, set the session id using SetTokenInformation with TokenSessionId) has none of these drawbacks.
What am I missing?
You're right. Your way is better and I plan to switch over to it went I get back to working on this.
Hi Eric, I have read your posts here and tried to recreate some of the suggestions on XP in anticipation of going to Vista soon. My problem is that whenever I use CreateProcessAsUser to start a process in another session I get error 2 - "The system cannot find the file specified". I think my use of CPAU is OK as it works fine if I use it based on a handle extracted from a process owned by the user of the console session. I can get processes owned by system and any other user working in Session 0 but I can't get a process to start in another FUS session.
If I use the SYSTEM process token, duplicate it, add the different session ID then use CPAU then I get error 2. Also, if I use the handle from the Explorer.exe process in the other session I also get error 2. Do you know if there is some kind of permissions that need to be set even though all the code is running as a SYSTEM user (either via a service or using PSEXEC from sysinternals).
Thanks,
Jeremy
Prior to Vista, there's a known limitation of CPAU (CreateProcessAsUser):
It doesn't work cross-session (typically from 0 to non 0) until a user logs on to that non 0 session...
If I remember correctly, the "expected" error code in that case is 2.
Eric, thanks for your reply.
I have now tried my code on vista and have no problem whatsover starting processes in other sessions. CPAU certainly seems to work more as expected on Vista than it does on XP when going across sessions.
Hi, James.You said,
" It would be better if the SERVICE_CONTROL_SESSIONCHANGE mechanism would tell you when new sessions are created, but it doesn't."
See
http://forums.microsoft.com/MSDN/ShowPost.aspx?PageIndex=2&SiteID=1&PostID=1057473Per this thread, I would expect you
could register your service for sessionchange notifications by calling SetServiceStatus() with the SERVICE_ACCEPT_SESSIONCHANGE flag. In that way, I would expect that your service would be notified of all SERVICE_CONTROL_SESSIONCHANGE notifications, and you would know a new session was starting if the event
type was set to WTS_CONSOLE_CONNECT or WTS_REMOTE_CONNECT.
Did you happen to try this? Very soon I will have need of implementing the same functionality you did, whereby I launch a process in a newly-created session prior to user logon. Like you said, a scheme for handling this other than polling would be nice. :-)
Thanks,
-IAmHe
The connect messages are actually reconnect messages.
They occur after user authentication when a user is reconnected to an existing session.
If the user didn't have one, a logon would occur instead.
If you're only interested in the creation of a new session at the physical console, then you can monitor logoffs and disconnects.
Shortly after either of these, a new session will be created.
I'm a little curious about the scenario requiring the creation of a per-session process prior to logon.
Can you share some more details?