特定のイベントが発生したときに、サブプロセスを使用して新しい子プロセスを生成する、長時間実行されデーモン化されたPythonプロセス。子プロセスは、親プロセスのスーパーユーザー権限を保持したまま、別のユーザー(「nobody」など)として実行するために生成されます。
私は現在使用しています
su -m nobody -c <program to execute as a child>
しかし、これは重いようで、非常にきれいに死ぬことはありません。
Suを使用する代わりにプログラムでこれを達成する方法はありますか?私はos.set * uidメソッドを見ていますが、Python std libのドキュメントはその領域ではかなりまばらです。
デーモンについて述べたので、Unixライクなオペレーティングシステムで実行していると結論付けることができます。これは、これを行う方法がオペレーティングシステムの種類によって異なるため、重要です。この回答は、onlyのみに適用されますnix(LinuxおよびMac OS Xを含む).
subprocess.Popenは、fork/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 __== '__main__':
main()
このスクリプトは次のように呼び出すことができます。
ルートとして起動...
(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
注子プロセスが終了するまで親プロセスを待機させるのは、デモ目的のみです。これは、親と子が端末を共有できるようにするためです。デーモンには端末がなく、子プロセスが終了するのをめったに待ちません。
os.setuid()
メソッドがあります。これを使用して、このスクリプトの現在のユーザーを変更できます。
解決策の1つは、子が開始する場所でos.setuid()
とos.setgid()
を呼び出してユーザーIDとグループIDを変更し、その後 os.exec * のいずれかを呼び出すことです。 _新しい子を生成するメソッド。新しく生成された子は、より強力なユーザーになることなく、より強力でないユーザーで実行されます。
もう1つの方法は、デーモン(マスタープロセス)が起動し、新しく生成されたすべてのプロセスが同じユーザーで実行されるときに実行することです。
詳細については、 setuidのマンページ をご覧ください。
実際、preexec_fnを使用した例はうまくいきませんでした。
別のユーザーからシェルコマンドを実行してその出力を取得するためにうまく機能している私のソリューションは次のとおりです。
apipe=subprocess.Popen('Sudo -u someuser /execution',Shell=True,stdout=subprocess.PIPE)
次に、プロセスstdoutから読み取る必要がある場合:
cond=True
while (cond):
line=apipe.stdout.getline()
if (....):
cond=False
私の場合だけでなく、それが役に立つことを願っています。