如何使用Ruby提示输入sudo密码? [英] How do you prompt for a sudo password using Ruby?

查看:95
本文介绍了如何使用Ruby提示输入sudo密码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常我发现自己需要编写脚本,这些脚本必须以普通用户身份执行某些部分,而以超级用户身份执行其他部分.我知道在SO上有一个类似的问题,答案是两次运行相同的脚本并以sudo的身份执行,但这对我来说还不够.有时候,在执行sudo操作后,我需要恢复为普通用户.

Often I find myself needing to write scripts that have to execute some portions as a normal user and other portions as a super user. I am aware of one similar question on SO where the answer was to run the same script twice and execute it as sudo, however that is not sufficient for me. Some times I need to revert to being a normal user after a sudo operation.

我已经用Ruby编写了以下内容

I have written the following in Ruby to do this

#!/usr/bin/ruby
require 'rubygems'
require 'highline/import'
require 'pty'
require 'expect'

def sudorun(command, password)
  `sudo -k`
  PTY.spawn("sleep 1; sudo -u root #{command} 2>&1") { | stdin, stdout, pid |
  begin
    stdin.expect(/password/) {
    stdout.write("#{password}\n")
    puts stdin.read.lstrip
                              }
  rescue Errno::EIO
  end
 }
end

不幸的是,如果用户输入了错误的密码,则使用该代码会使脚本崩溃.理想情况下,它应该使用户3尝试正确获取sudo密码.我该如何解决?

Unfortunately, using that code if the user enters the wrong password the script crashes. Ideally it should give the user 3 tries to get the sudo password right. How do I fix this?

我正在Linux Ubuntu BTW上运行它.

I am running this on Linux Ubuntu BTW.

推荐答案

在我看来,运行在内部使用sudo进行填充的脚本是错误的.更好的方法是让用户使用sudo运行整个脚本,并让该脚本派出较弱特权的孩子执行任务:

In my opinion, running a script that does stuff internally with sudo is wrong. A better approach is to have the user run the whole script with sudo, and have the script fork lesser-privileged children to do stuff:

# Drops privileges to that of the specified user
def drop_priv user
  Process.initgroups(user.username, user.gid)
  Process::Sys.setegid(user.gid)
  Process::Sys.setgid(user.gid)
  Process::Sys.setuid(user.uid)
end

# Execute the provided block in a child process as the specified user
# The parent blocks until the child finishes.
def do_as_user user
  unless pid = fork
    drop_priv(user)
    yield if block_given?
    exit! 0 # prevent remainder of script from running in the child process
  end
  puts "Child running as PID #{pid} with reduced privs"
  Process.wait(pid)
end

at_exit { puts 'Script finished.' }

User = Struct.new(:username, :uid, :gid)
user = User.new('nobody', 65534, 65534)

do_as_user(user) do
  sleep 1 # do something more useful here
  exit! 2 # optionally provide an exit code
end

puts "Child exited with status #{$?.exitstatus}"
puts 'Running stuff as root'
sleep 1

do_as_user(user) do
  puts 'Doing stuff as a user'
  sleep 1
end

此示例脚本具有两个帮助程序方法. #drop_priv接受一个定义了用户名,uid和gid的对象,并且正确会减小执行进程的权限. #do_as_user方法在屈服提供的块之前,在子进程中调用#drop_priv.注意使用#exit!以防止孩子在块外运行脚本的任何部分,同时避免使用at_exit钩子.

This example script has two helper methods. #drop_priv takes an object with username, uid, and gid defined and properly reduces the permissions of the executing process. The #do_as_user method calls #drop_priv in a child process before yielding to the provided block. Note the use of #exit! to prevent the child from running any part of the script outside of the block while avoiding the at_exit hook.

通常会忽略以下安全问题:

Often overlooked security concerns to think about:

  • 打开文件描述符的继承
  • 环境变量过滤
  • 在chroot中运行孩子?

根据脚本的工作情况,可能需要解决所有这些问题. #drop_priv是处理所有这些问题的理想场所.

Depending on what the script is doing, any of these may need to be addressed. #drop_priv is an ideal place to handle all of them.

这篇关于如何使用Ruby提示输入sudo密码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆