web-dev-qa-db-ja.com

PythonでSudo権限を持つファイルに書き込みます

次のコードは、非rootユーザーがSudo特権を持っている場合でも、rootが所有するファイルに対して非rootユーザーが実行するとエラーをスローします。

_try:
  f = open(filename, "w+")
except IOError:
  sys.stderr.write('Error: Failed to open file %s' % (filename))
f.write(response + "\n" + new_line)
f.close()
_

open(filename, "w+")をSudo特権で実行する方法、またはこれを行う代替機能はありますか?

12
user2824889

いくつかのオプションがあります:

  • ルートとして、またはSudoを使用してスクリプトを実行します
  • Setuidビットを設定し、rootがスクリプトを所有するようにします(ただし、多くのシステムでは、これはスクリプトでは機能せず、スクリプトは誰でも呼び出すことができます)
  • ルート(os.geteuid() != 0)として実行していないことを検出し、Sudo infront(パスワードの入力をユーザーに要求します)で自分自身を呼び出して終了します。

import os
import sys
import subprocess

if os.geteuid() == 0:
    print("We're root!")
else:
    print("We're not root.")
    subprocess.call(['Sudo', 'python3', *sys.argv])
    sys.exit()

呼び出しは次のようになります。

$ python3 be_root.py
We're not root.
Password:
We're root!
10
L3viathan

TL; DR:

L3viathanの返信 synaxErrorがあります 編集:Python 3.5+で正常に動作します。 Python 3.4.3(Ubuntu 16.04でデフォルトで配布されています)以下のバージョンは次のとおりです。

_if os.geteuid() == 0:
    # do root things
else:
    subprocess.call(['Sudo', 'python3'] + sys.argv)  # modified
_

しかし、ユースケースではコードを簡単にするため、別のアプローチを使用しました。

_if os.geteuid() != 0:
    os.execvp('Sudo', ['Sudo', 'python3'] + sys.argv)
# do root things
_

説明

L3viathanの応答PEP 448 に依存します。これはPython 3.5に含まれ、スター引数の展開が許可される追加のコンテキストを導入しました。 Python 3.4以前では、リスト連結を使用して同じことを行うことができます。

_import os
import sys
import subprocess

if os.geteuid() == 0:
    print("We're root!")
else:
    print("We're not root.")
    subprocess.call(['Sudo', 'python3'] + sys.argv)  # modified
_

ただし、note:subprocess.call()は子プロセスを起動します。つまり、rootがスクリプトの実行を終了した後、元のユーザーは引き続きスクリプトを実行します。上手。これは、元のスクリプトが終了したときに、昇格を必要とするロジックを実行しようとしないように、昇格したロジックを_if/else_ブロックの片側に配置する必要があることを意味します(L3viathanの例ではこれを実行します)。

これは必ずしも悪いことではありません。通常のロジックと高度なロジックの両方を同じスクリプトで記述し、うまく分離できることを意味しますが、私のタスクにはすべてのロジックのルートが必要です。他のブロックが空になる場合、インデントレベルを無駄にしたくありませんでした。また、子プロセスの使用が物事にどのように影響するかを理解していなかったため、これを試しました。

_import os
import sys
import subprocess

if os.geteuid() != 0:
    subprocess.call(['Sudo', 'python3'] + sys.argv)

# do things that require root
_

...そしてもちろん、rootが終了した後、通常のユーザーはスクリプトの実行を再開し、rootを必要とするステートメントを実行しようとしたため、それは壊れました。

そして、私は この要点os.execvp()を推奨しています-子を起動する代わりに実行中のプロセスを置き換えます:

_import os
import sys

if os.geteuid() != 0:
    os.execvp('Sudo', ['Sudo', 'python3'] + sys.argv)  # final version

# do things that require root
_

これは予想どおりに動作するように見え、インデントレベルと3行のコードを節約します。

警告:os.execvp()については10分前には知りませんでしたが、その使用に関する落とし穴や微妙な点についてはまだ何も知りません。 YMMV。

7
Peter Henry

スクリプトは、root権限がなければユーザーを変更できないため、実行される権限に制限されます。

ロブが言ったように、ファイルのアクセス許可を変更せずにこれを行う唯一の方法は、Sudoで実行することです。

Sudo python ./your_file.py
1
Matt Olan

Sudoを使用する可能性があるため、実際に使用しない場合は特権を付与しません。したがって、他の人が示唆したように、おそらくSudoを使用してプログラムを開始する必要があります。しかし、このアイデアが気に入らない場合(その理由はわかりません)、他のトリックを行うことができます。

スクリプトは、root権限で実行されているか、ユーザー権限でのみ動作するかを確認できます。実際には、スクリプトはより高い特権で自分自身を実行できます。ここに例を示します(パスワードをソースコードに保存することはお勧めできません)。

import os.path
import subprocess

password_for_Sudo = 'pass'

def started_as_root():
    if subprocess.check_output('whoami').strip() == 'root':
        return True
    return False

def runing_with_root_privileges():
    print 'I have the power!'

def main():
    if started_as_root():
        print 'OK, I have root privileges. Calling the function...'
        runing_with_root_privileges()
    else:
        print "I'm just a user. Need to start new process with root privileges..."
        current_script = os.path.realpath(__file__)
        os.system('echo %s|Sudo -S python %s' % (password_for_Sudo, current_script))

if __name__ == '__main__':
    main()

出力:

$ python test.py
I'm just a user. Need to start new process with root privileges...
OK, I have root privileges. Calling the function...
I have the power!

$ Sudo python test.py
OK, I have root privileges.
Calling the function...
I have the power!
1
Adam

L3viathanの返信が好きです。 4番目のオプションを追加します。subprocess.Popen()を使用してshコマンドを実行し、ファイルを書き込みます。 subprocess.Popen('Sudo echo \'{}\' > {}'.format(new_line, filename))のようなもの。

0
portusato