web-dev-qa-db-ja.com

スクリプトのユーザーがルートのような権限を持っているかどうかを確認する最良の方法は何ですか?

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.")

これがチェックを行う最良の方法ですか?他のベストプラクティスはありますか?

61
Paul Hoffman

「許可よりも赦しを求めやすい」という原則の下で:

_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_をいじってはいけません。

27
msw

os.geteuidは、有効なユーザーIDを取得します。これは、まさにあなたが望むものです。そのため、このようなチェックを実行するより良い方法は考えられません。少し不確かなのは、タイトルの「ルートに似ている」ことです。コードはexactlyrootをチェックし、それについて「いいね」はありません。 「ルートに似ているがルートではない」とは、つまり「完全にルート」とは異なる何かを意味する場合、おそらく明確にすることができます、ありがとう!

62
Alex Martelli

ユーザーに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)。

11
jcarballo

さまざまな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を認識して使用する準備ができたことは、システム権限の制御された委任のためのはるかに普及したツール)。

7
Jim Dennis

質問の2番目の部分への回答

(コメントボックスが小さすぎて申し訳ありません)

ポール・ホフマン、あなたは正しいです、私は組み込み関数を扱うあなたの質問の一部だけを取り上げましたが、それが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のような汎用性についてはコメントしません。

3
msw

環境変数でSudoを確認したい:

 os.environ.keys()の 'Sudo_UID'ではない場合:
 print "このプログラムにはスーパーユーザーの特権が必要です。" 
 sys.exit(1)
2
vossman77

Linuxの場合:

def is_root():
    return os.geteuid() == 0
2
dimon4eg

私のアプリは次のコードで動作します:

import os
user = os.getenv("Sudo_USER")
if user is None:
    print "This program need 'Sudo'"
    exit()
2
Guillaume

それはすべて、あなたがあなたのアプリをどれだけポータブルにしたいかに依存します。ビジネスを意味する場合、管理者アカウントが常に0に等しいとは限りません。これは、euid 0をチェックするだけでは不十分であることを意味します。問題は、あるコマンドがあなたがrootであるかのように動作し、次がpermission denied(SELinux&co。を考えてください)で失敗する状況があることです。したがって、適切に失敗し、EPERM errnoが適切な場合はいつでもチェックすることをお勧めします。

0
Stan