Monday, December 06, 2010

Starting process in the logged session under the local system account

Introduction

This article describes how to use CreateProcessAsUser with the token duplicated from the system process in the current logged session. The common concept is to start process when a new session appears and to terminate it when the session connection status is changed to “disconnected” or the session is closed. The process, which our sample service starts, is the same executable file that the service itself, but started with the parameter “app”. The singularity of the process consists in the permission restriction for the users without administrator privileges.

This article is a logical continuing of another one – Monitoring of logon/logout in terminal and client sessions
Waiting for the system process in the session
Let’s describe the situation when we get the notification about session log in event. We want to start a process at that moment as the user that is the owner of our service. It is NT AUTHORITY\SYSTEM. To call the CreateProcessAsUser function we need to have the handle to the primary token that represents a user with TOKEN_QUERY, TOKEN_DUPLICATE access rights. We could duplicate the token of the current module (our service), it is running as NT AUTHORITY\SYSTEM. But it is running in the console session with session ID 0.  What if we need the handle to the token of the process that is running in the same session, which we want to run a process in? There is a small nuance – in the moment when we get the session connecting notification, there can be no process in the session, from which we could duplicate the token. So there has to be a thread for waiting process run by the user that we need, and with the session ID of the process that matches the logged session ID, so that we will be able to duplicate the token of this process. As in the previous article project sample, boost::thread is used. Here is the class-wrapper for work with the thread:

typedef boost::shared_ptr<boost::thread> ThreadPtr;
   class ThreadHolder
   {
       boost::shared_ptr<CThreadForSession> m_pThreadParams;
       ThreadPtr m_thread;
       bool m_bStopInDestructor;
   public:
       ThreadHolder(boost::shared_ptr<CThreadForSession> pThreadParams, ThreadPtr thread)
           : m_bStopInDestructor(false)
       {
       }
       ~ThreadHolder()
       {
           if (m_bStopInDestructor)
           {
               m_pThreadParams->Stop();
               m_thread->join();
           }
       }
       void SetStopEvent (bool stop) { m_bStopInDestructor = stop; }
   };

This class contains the pointer to the thread to stop it in destructor and the pointer to the class, which implements the function executing in the thread - class CThreadForSession, to set stop event in the destructor of the ThreadHolder class. Here is the CThreadForSession class with the function running in the separate thread:

   class CThreadForSession
   {
       int m_sid;
       sm::WinNotificationEvent m_stopEvent;
       ISObserver * m_pObserver;
   public:

Read more: Codeproject