检查Python脚本的用户是否具有根类权限的最佳实践是什么?

我有一个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()的不可移植性, os.geteuid()你可能不应该使用/etc os.geteuid()

os.geteuid获得有效的用户ID,这正是你想要的,所以我想不出有什么更好的方法来执行这样的检查。 有一点是不确定的,就是标题中的“根类”:你的代码检查的是完全 root ,对它没有“喜欢”,事实上我不知道“根类但不是根”意味着什么 -所以,如果你的意思不同于“完全根”,也许你可以澄清,谢谢!

如果你真的希望你的代码在各种各样的Linuxconfiguration下健壮,我build议你考虑一些人可能使用SELinux,文件系统ACL或Linux内核中的“function”特性自v.2.2左右。 你的过程可能在一些使用SELinux的包装器,或者一些Linux能力库(比如libcap2 libcap-ng ,或者fscaps或者elfcap)下运行,通过一些更加奇特的东西,例如Niels Provos的精彩和可悲的低估的systrace系统。

所有这些都是你编写的代码可能以非root用户身份运行的方式,但是你的进程可能被委派了必要的访问权限来执行它的工作而不用EUID == 0。

所以我build议你考虑编写你的代码,通过包装可能由于权限或exception处理代码的其他问题而失败的操作。 如果您正在执行各种操作(例如,使用subprocess模块),您可能会提供以sudo (例如命令行,环境或.rc文件选项)作为前缀的所有此类调用。 如果它是以交互方式运行,那么可以提供重新执行任何使用sudo来引发权限相关exception的sudo (可选地,只要在os.environ ['PATH'上findsudo ])。

总的来说,大多数Linux和UNIX系统的大部分pipe理仍然是由“root”特权用户完成的。 然而,这是一所老学校,作为程序员,我们应该尝试支持更新的模型。 尝试你的操作,并让exception处理完成它的工作,让你的代码可以在任何透明地允许你需要的操作的系统下工作,并且知道并准备好使用sudo是一个很好的触摸(到目前为止,广泛的工具来控制系统权限的授权)。

回答问题的第二部分

(对不起,评论框太小)

保罗·霍夫曼(Paul Hoffman),你是对的,我只讨论处理内部函数的问题的一部分,但如果它不能处理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 

现在我们回到exception处理。 我将拒绝评论subprocess模块的类似Java的泛化。

您可以提示用户使用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开关更新用户的caching凭证(请参阅man sudo )。

我的应用程序使用这个代码:

 import os user = os.getenv("SUDO_USER") if user is None: print "This program need 'sudo'" exit() 

我喜欢在环境variables中检查sudo:

如果在os.environ.keys()中不是'SUDO_UID':
  打印“这个程序需要超级用户权限。”
   sys.exit(1)

这一切都取决于你想要你应用程序的便携性。 如果你的意思是商务,我们必须假设pipe理员帐户不总是等于0.这意味着检查euid 0是不够的。 问题是,在某些情况下,一个命令的行为就像是root一样,而下一个将会因权限被拒绝而失败(想想SELinux&co。)。 因此,只要适当,优雅地失败并且检查EPERM errno是更好的。