Запустить блок Ruby от имени конкретного пользователя ОС? - PullRequest
3 голосов
/ 28 декабря 2010

Можете ли вы выполнить блок кода Ruby от имени другого пользователя ОС?

То, что я в идеале хочу, выглядит примерно так:

user("christoffer") do
  # do something
end

Возможно?

Ответы [ 2 ]

7 голосов
/ 28 декабря 2010

Этот код может делать то, что вы хотите.Обработка ошибок зависит от вас.; -)

require 'etc'

def as_user(user, &block)
    u = Etc.getpwnam(user)
    Process.fork do
        Process.uid = u.uid
        block.call(user)
    end
end

puts("caller PID = #{Process.pid}")
puts("caller UID = #{Process.uid}")
as_user "bmc" do |user|
    puts("In block as #{user} (uid=#{Process.uid}), pid is #{Process.pid}")
end

Обратите внимание, однако, что для этого потребуется, чтобы вы запускали Ruby как root или как setuid-to- root, что имеет серьезные последствия для безопасности.

0 голосов
/ 01 октября 2018

Принятый ответ меняет UID, но выполнение этого само по себе может привести к неожиданным результатам при создании файлов или дочерних процессов.Попробуйте:

as_user 'bmc' do |user|
  File.open('/tmp/out.txt', 'w')
end

Вы обнаружите, что файл был создан как пользователь root, что не соответствует ожиданиям.

Поведение менее предсказуемо при запуске команды с использованием backtics.Следующие результаты, вероятно, не соответствуют ожиданиям:

as_user 'puppet' do
  puts `whoami`
  puts `id`
  puts `whoami; id`
end

Тестирование в системе Linux, первое puts напечатано root.id напечатал следующее:

uid=1052(chet) gid=0(root) euid=0(root) groups=0(root)

Финал puts не согласен:

puppet
uid=1052(chet) gid=0(root) groups=0(root)

Чтобы получить согласованное поведение, обязательно установите эффективный UID:

def as_user(user, &block)
    u = Etc.getpwnam(user)
    Process.fork do
        Process.uid = Process.euid = u.uid
        block.call(user)
     end
end

Может быть полезно получить значение обратно из дочернего процесса.Добавление небольшого веселья IPC дает:

require 'etc'

def as_user(user, &block)
  u = (user.is_a? Integer) ? Etc.getpwuid(user) : Etc.getpwnam(user)

  reader, writer = IO.pipe

  Process.fork do
    # the child process won't need to read from the pipe
    reader.close

    # use primary group ID of target user
    # This needs to be done first as we won't have
    # permission to change our group after changing EUID
    Process.gid = Process.egid = u.gid

    # set real and effective UIDs to target user
    Process.uid = Process.euid = u.uid

    # get the result and write it to the IPC pipe
    result = block.call(user)
    Marshal.dump(result, writer)
    writer.close

    # prevent shutdown hooks from running
    Process.exit!(true)
  end

  # back to reality... we won't be writing anything
  writer.close

  # block until there's data to read
  result = Marshal.load(reader)

  # done with that!
  reader.close

  # return block result
  result
end

val = as_user 'chet' do
  `whoami` + `id` + `whoami; id`
end

puts "back from wonderland: #{val}"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...