Принятый ответ меняет 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}"