alexsilva / supervisor

Supervisor process control system for Windows
http://supervisord.org
Other
118 stars 26 forks source link

Subprocesses not running with specified user but SYSTEM #35

Closed sdebionne closed 3 years ago

sdebionne commented 3 years ago

When supervisor is installed and running as a service, the processes spawn by supervisor are not running with the user specified in the configuration:

[program:foo]
command=foo.exe
user=bar

Task Manager shows SYSTEM as User name for foo.exe.

Here is my env:

python                    3.7.10               h6244533_0
pywin32                   228                      pypi_0    pypi
supervisor-win            4.6.0                    pypi_0    pypi
sdebionne commented 3 years ago

I am adding a configuration and repro:

; supervisor config file
[program:test]
command=python.exe "C:/Repro/test.py"
user=debionne
environment=PATH="C:\Miniconda3"

where C:/Repro/test.py:

import psutil
for process in psutil.process_iter():
    try:
        if process.name() == 'python.exe':
            print('Process: %s, PID: %s, Owner: %s' % (process.name(), process.pid, process.username()))
    except psutil.AccessDenied:
        print('Process: %s, PID: %s, Owner: DENIED' % (process.name(), process.pid))

gives Process: python.exe, PID: 18168, Owner: NT AUTHORITY\SYSTEM

sdebionne commented 3 years ago

Looking at the code, I see that this is actually not implemented. I'll make a PR so that this is properly reported with a NotImplementedError exception.

alexsilva commented 3 years ago

Changing the process user on windows is quite complicated. There is the runas program that helps but it asks for a password explicitly which ends up not being useful.

Example runas.exe /user:name@outlook.com "cmd.exe /c "E:\supervisor\program.cmd""

alexsilva commented 3 years ago

I did some of the necessary work and it looks like it works.

The configuration looks like this (a little insecure due to the password).

[program:cmd]
command=cmd.exe
user=user@outlook.com
pwd=pass

A limitation is that the supervisor process needs to start with a System accounts Changes: https://github.com/alexsilva/supervisor/commit/0fa095e5729ac32560bf7580af162e0b99be805b

sdebionne commented 3 years ago

Thanks for looking into this!

Sorry for breaking the tests, I did not noticed that Travis was not configured on merge requests.

I see that you are using CreateProcessAsUser. I whish there is a way to impersonate a user without giving credentials explicitly but with special privileges to the service user... It looks like there might be ways to CreateProcessAsUser and LogonUser without password, as describe in 5.3. CreatePureUserToken (showing more sophisticated usage of ZwCreateToken) of this Code Project but it's not clear to me how it works. And this solution probably has some limitation regarding access to network ressources which is my main motivation to run as different user in the first place.

Would it be possible to had domain user support? Or is it already supported with the typical domain\user syntax?

alexsilva commented 3 years ago

Added domain support with syntax: domain\user

https://github.com/alexsilva/supervisor/commit/c8a551f74b1c0b67c722edc99a2a252ce9b32eea

sdebionne commented 3 years ago

Thank you so much, I did a quick test with the test.py mentioned above and a domain's user: it works. Just a few comments:

Quoting Windows Developer :

When you have finished using the password, clear the password from memory by calling the SecureZeroMemory function.

To better deal with the plaintext password, I was looking at Handling Password. Do you think any of these is adequate?

alexsilva commented 3 years ago

It has a possibility to encrypt the password with the functions of api:

pywin32.CryptProtectDatat pywin32.CryptUnprotectData

I just don't know yet if it will work

Encrypts data using a session key derived from current user's logon credentials

The problem is that it depends on a password to encrypt another passoword.