8

一部の部分を通常のユーザーとして実行し、他の部分をスーパー ユーザーとして実行する必要があるスクリプトを作成する必要があることがよくあります。同じスクリプトを 2 回実行して sudo として実行するという SO に関する同様の質問を 1 つ知っていますが、それでは十分ではありません。sudo 操作の後、通常のユーザーに戻す必要がある場合があります。

これを行うためにRubyで次のように記述しました

#!/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 パスワードを正しく取得できるようにする必要があります。これを修正するにはどうすればよいですか?

これをLinux Ubuntu BTWで実行しています。

4

4 に答える 4

8

私の意見では、sudo を使用して内部的に何かを行うスクリプトを実行するのは間違っています。より良いアプローチは、ユーザーに sudo を使用してスクリプト全体を実行させ、スクリプトに権限の低い子供たちを fork させて何かを実行させることです。

# 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

このサンプル スクリプトには 2 つのヘルパー メソッドがあります。#drop_priv は、ユーザー名、uid、および gid が定義されたオブジェクトを取得し、実行中のプロセスの権限を適切に減らします。#do_as_user メソッドは、提供されたブロックに譲る前に、子プロセスで #drop_priv を呼び出します。#exit の使用に注意してください。at_exit フックを回避しながら、子がブロックの外側でスクリプトの一部を実行できないようにします。

見過ごされがちなセキュリティ上の懸念事項:

  • 開いているファイル記述子の継承
  • 環境変数のフィルタリング
  • chroot で子供を実行しますか?

スクリプトの実行内容によっては、これらのいずれかに対処する必要がある場合があります。#drop_priv は、それらすべてを処理するのに理想的な場所です。

于 2012-10-02T18:04:16.523 に答える
5

可能であれば、ルートとして実行したいものを別のファイルに移動し、system()関数を使用してsudoプロンプトなどを含めてsudoとして実行できます。

system("sudo ruby stufftorunasroot.rb")

関数はブロックしているため、プログラムのsystem()流れを変更する必要はありません。

于 2012-09-28T08:15:39.003 に答える
3

これがあなたの望むものか必要なものかはわかりませんが、試してみましたか ( /usr/lib/openssh/gnome-ssh-askpassなどの値を持つsudo -AWeb または man ページを検索してください)。これは、GUI 環境でユーザーにグラフィカルなパスワード ダイアログを表示する必要があるときに使用します。SUDO_ASKPASS

これが間違った答えである場合は申し訳ありませんが、おそらくコンソールに残りたいと考えています.

于 2012-09-30T07:36:42.383 に答える
1
#!/usr/bin/ruby
# ... blabla, other code
# part which requires sudo:
system "sudo -p 'sudo password: ' #{command}"
# other stuff
# sudo again
system "sudo -p 'sudo password: ' #{command}"
# usually sudo 'remembers' that you just authenticated yourself successfuly and doesn't ask for the PW again...
# some more code...
于 2012-09-28T13:43:41.690 に答える