Поскольку вы упомянули демона, я могу заключить, что вы работаете в Unix-подобной операционной системе. Это важно, потому что, как это сделать, это зависит от операционной системы. Этот ответ относится только к Unix, включая Linux и Mac OS X.
- Определить функцию, которая будет устанавливать GID и УИД запущенного процесса.
- Передайте эту функцию в качестве параметра preexec_fn к subprocess.Popen
subprocess.Popen будет использовать вилку/EXEC модели использовать preexec_fn. Это эквивалентно вызову os.fork(), preexec_fn() (в дочернем процессе) и os.exec() (в дочернем процессе) в этом порядке. Поскольку os.setuid, os.setgid и preexec_fn поддерживаются только в Unix, это решение не переносимо для других видов операционных систем.
Следующий код представляет собой скрипт (Python 2.4+), что свидетельствует о том, как это сделать:
import os
import pwd
import subprocess
import sys
def main(my_args=None):
if my_args is None: my_args = sys.argv[1:]
user_name, cwd = my_args[:2]
args = my_args[2:]
pw_record = pwd.getpwnam(user_name)
user_name = pw_record.pw_name
user_home_dir = pw_record.pw_dir
user_uid = pw_record.pw_uid
user_gid = pw_record.pw_gid
env = os.environ.copy()
env[ 'HOME' ] = user_home_dir
env[ 'LOGNAME' ] = user_name
env[ 'PWD' ] = cwd
env[ 'USER' ] = user_name
report_ids('starting ' + str(args))
process = subprocess.Popen(
args, preexec_fn=demote(user_uid, user_gid), cwd=cwd, env=env
)
result = process.wait()
report_ids('finished ' + str(args))
print 'result', result
def demote(user_uid, user_gid):
def result():
report_ids('starting demotion')
os.setgid(user_gid)
os.setuid(user_uid)
report_ids('finished demotion')
return result
def report_ids(msg):
print 'uid, gid = %d, %d; %s' % (os.getuid(), os.getgid(), msg)
if __name__ == '__main__':
main()
Вы можете вызывать этот скрипт так:
Start как корень ...
(hale)/tmp/demo$ sudo bash --norc
(root)/tmp/demo$ ls -l
total 8
drwxr-xr-x 2 hale wheel 68 May 17 16:26 inner
-rw-r--r-- 1 hale staff 1836 May 17 15:25 test-child.py
Стать некорневая в дочернем процессе ...
(root)/tmp/demo$ python test-child.py hale inner /bin/bash --norc
uid, gid = 0, 0; starting ['/bin/bash', '--norc']
uid, gid = 0, 0; starting demotion
uid, gid = 501, 20; finished demotion
(hale)/tmp/demo/inner$ pwd
/tmp/demo/inner
(hale)/tmp/demo/inner$ whoami
hale
Когда дочерний процесс завершается, мы возвращаемся к корню в родительском ...
(hale)/tmp/demo/inner$ exit
exit
uid, gid = 0, 0; finished ['/bin/bash', '--norc']
result 0
(root)/tmp/demo$ pwd
/tmp/demo
(root)/tmp/demo$ whoami
root
Примечание, что наличие родительского процесса ждать для дочернего процесса выхода для демонстрационных целей только. Я сделал это так, чтобы родитель и ребенок могли делиться терминалом. У демона нет терминала и редко будет ждать, пока дочерний процесс выйдет.
* «редко ждем, чтобы процесс выхода из ребенка» * может привести ко многим процессам зомби (долгоживущие родительские, недолговечные дочерние процессы). – jfs
Возможно, это очевидно (не для меня), но ... вы * должны * сначала изменить 'gid', как показано в примере! – Jamie
Обратите внимание, что в приведенном выше примере используется только ** основной gid пользователя **, если вы хотите использовать ** ВСЕ ** из групп пользователя, тогда вы можете использовать ** os.initgroups (user_name, user_gid) ** вместо os.setgid , Для этого необходимо передать имя пользователя в demote() –