title: Launch external process as user while running as root
body: <p>I,m writing a mono application which is intended to run at startup as root (upstart + mono-service) and listen to user login/logout events. When user loggs in I start another mono service to listen to session events. But it should not run as root, but as session owner. I have access to session owner's name, uid, gid. </p>
  
  <p>My problem is someow similar to <a href="https://stackoverflow.com/questions/31646768/start-a-process-as-user-from-an-process-running-as-admin">Start a process as user from an process running as admin</a> , but for linux.</p>
  
  <p>So how to run external process as specified user while running from root properly?</p>
  
  <p><strong>Edit:</strong></p>
  
  <p>Here's my solution:</p>
  
  <p>According to <a href="http://pages.infinit.net/ctech/20040405-1133.html" rel="nofollow">http://pages.infinit.net/ctech/20040405-1133.html</a> I've tried to impersonate to user while starting process, and it works well as I can see for now.</p>
  
  <pre><code>public class SpawnerService : ServiceBase
  {
      public SpawnerService ()
      {
          logger = new StreamWriter (new FileStream("/home/username/Log.txt", FileMode.Append));
  
          info = new ProcessStartInfo {
              FileName = "/usr/bin/mono-service",
              Arguments = "/home/username/SlaveService.exe",
              UseShellExecute = false,
              CreateNoWindow = true
          };
      }
  
      protected override void OnStart (string[] args)
      {
          logger.WriteLine ("Spawner service started");
          logger.Flush ();
  
          var user = new WindowsIdentity ("username");
          logger.WriteLine ("Trying to mimc to {0}, {1}", user.Name,user.Token.ToString());
          logger.Flush ();
  
          WindowsImpersonationContext wic = null;
          try {
              wic = user.Impersonate ();
              Process.Start (info);
              logger.WriteLine ("Seems allright");
              logger.Flush ();
          }
          catch (Exception) {
              logger.WriteLine ("Seems failed");
              logger.Flush ();
          }
          finally {
              if (wic != null) {
                  wic.Undo ();
                  wic = null;
              }
          }
      }
  
      protected override void OnStop ()
      {
          logger.WriteLine ("Spawner service stopped");
          logger.Flush ();
      }
  
      private ProcessStartInfo info;
      private StreamWriter logger;
  }
  </code></pre>
  
  <p>Is this a reliable method? Or are there some better ones?</p>