Pythonスクリプトは/ etcでのファイルの移動、apt-getでのインストールなど、ルートレベルの特権を必要とする多くのことを実行します。現在、持ってる:
if os.geteuid() != 0:
exit("You need to have root privileges to run this script.\nPlease try again, this time using 'Sudo'. Exiting.")
これがチェックを行う最良の方法ですか?他のベストプラクティスはありますか?
「許可よりも赦しを求めやすい」という原則の下で:
_try:
os.rename('/etc/foo', '/etc/bar')
except IOError as e:
if (e[0] == errno.EPERM):
print >> sys.stderr, "You need root permissions to do this, laterz!"
sys.exit(1)
_
os.geteuid()
の移植性が心配な場合は、おそらく_/etc
_をいじってはいけません。
os.geteuid
は、有効なユーザーIDを取得します。これは、まさにあなたが望むものです。そのため、このようなチェックを実行するより良い方法は考えられません。少し不確かなのは、タイトルの「ルートに似ている」ことです。コードはexactlyroot
をチェックし、それについて「いいね」はありません。 「ルートに似ているがルートではない」とは、つまり「完全にルート」とは異なる何かを意味する場合、おそらく明確にすることができます、ありがとう!
ユーザーにSudoアクセスを要求できます。
import os, subprocess
def Prompt_Sudo():
ret = 0
if os.geteuid() != 0:
msg = "[Sudo] password for %u:"
ret = subprocess.check_call("Sudo -v -p '%s'" % msg, Shell=True)
return ret
if Prompt_Sudo() != 0:
# the user wasn't authenticated as a sudoer, exit?
Sudo -v
スイッチは、ユーザーのキャッシュされた資格情報を更新します(man Sudo
)。
さまざまなLinux構成にわたってコードを本当に堅牢にしたい場合は、誰かがSELinux、ファイルシステムACL、またはLinuxカーネルにある「機能」機能を使用している可能性があるコーナーケースを検討することをお勧めします。バージョン2.2以降。プロセスは、SELinuxを使用したラッパー、または libcap2libcap-ng 、または fscaps などのLinux機能ライブラリで実行されている可能性があります elfcap Niels Provosの素晴らしい、そして残念ながら過小評価されている systrace システムのような、もっとエキゾチックなものを介して。
これらはすべて、コードを非ルートとして実行する方法ですが、EUID == 0を使用せずにプロセスを実行するために必要なアクセスがプロセスに委任されている場合があります。
したがって、アクセス許可や例外処理コードのその他の問題が原因で失敗する可能性のある操作をラップすることにより、コードをよりPython的に記述することを検討することをお勧めします。さまざまな操作を実行するためにシェルアウトしている場合(たとえば、subprocess
モジュールを使用)、そのようなすべての呼び出しの前にSudo
を付けることを提案できます(コマンドライン、環境、または.rcファイルオプションとして) 、 例えば)。インタラクティブに実行されている場合、Sudo
を使用して、アクセス許可に関連する例外を発生させるコマンドを再実行することを提案できます(オプションで、os.environ ['PATH']にSudo
が見つかった場合のみ)。
全体として、ほとんどのLinuxおよびUNIXシステムでは、管理のほとんどが「ルート」特権ユーザーによって行われていることは事実です。しかし、それは古い学校であり、プログラマーとして、新しいモデルをサポートしようとする必要があります。操作を試行し、例外処理にジョブを実行させると、必要な操作を透過的に許可するシステムの下でコードを動作させることができ、Sudo
を認識して使用する準備ができたことは、システム権限の制御された委任のためのはるかに普及したツール)。
(コメントボックスが小さすぎて申し訳ありません)
ポール・ホフマン、あなたは正しいです、私は組み込み関数を扱うあなたの質問の一部だけを取り上げましたが、それがapt-get
。優先ライブラリは少し冗長ですが、それは仕事をします:
>>> apt_get = ['/usr/bin/apt-get', 'install', 'python']
>>> p = subprocess.Popen(apt_get, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> p.wait()
100 # Houston, we have a problem.
>>> p.stderr.read()
'E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)'
'E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?\n'
ただし、Popen
は一般化されたツールであり、便宜上ラップすることができます。
$ cat apt.py
import errno
import subprocess
def get_install(package):
cmd = '/usr/bin/apt-get install'.split()
cmd.append(package)
output_kw = {'stdout': subprocess.PIPE, 'stderr': subprocess.PIPE}
p = subprocess.Popen(cmd, **output_kw)
status = p.wait()
error = p.stderr.read().lower()
if status and 'permission denied' in error:
raise OSError(errno.EACCES, 'Permission denied running apt-get')
# other conditions here as you require
$ python
>>> import apt
>>> apt.get_install('python')
Traceback ...
OSError: [Errno 13] Permission denied running apt-get
そして、例外処理に戻りました。サブプロセスモジュールのJavaのような汎用性についてはコメントしません。
環境変数でSudoを確認したい:
os.environ.keys()の 'Sudo_UID'ではない場合: print "このプログラムにはスーパーユーザーの特権が必要です。" sys.exit(1)
Linuxの場合:
def is_root():
return os.geteuid() == 0
私のアプリは次のコードで動作します:
import os
user = os.getenv("Sudo_USER")
if user is None:
print "This program need 'Sudo'"
exit()
それはすべて、あなたがあなたのアプリをどれだけポータブルにしたいかに依存します。ビジネスを意味する場合、管理者アカウントが常に0に等しいとは限りません。これは、euid 0をチェックするだけでは不十分であることを意味します。問題は、あるコマンドがあなたがrootであるかのように動作し、次がpermission denied(SELinux&co。を考えてください)で失敗する状況があることです。したがって、適切に失敗し、EPERM errnoが適切な場合はいつでもチェックすることをお勧めします。