While writing a Ruby script that runs as root, you need to take some action on behalf of another user: say, run an external program or create a file.
Simply set Process.euid to the UID of the user. When you e done, set it back to its previous value (that is, roots UID). Heres a method Process.as_uid that runs a code block under a different user ID and resets it at the end:
module Process def as_uid(uid) old_euid, old_uid = Process.euid, Process.uid Process.euid, Process.uid = uid, uid begin yield ensure Process.euid, Process.uid = old_euid, old_uid end end module_function(:as_uid) end
When a Unix process tries to do something that requires special permissions (like access a file), the permissions are checked according to the "effective user ID" of the process. The effective user ID starts out as the user ID you used when you started the process, but if you e root you can change the effective user ID with Process.euid=. The operating system will treat you as though you were really that user.
This comes in handy when you e administering a system used by others. When someone asks you for help, you can write a script that impersonates them and runs the commands they don know how to run. Rather than creating files as root and using chown to give them to another user, you can create the files as the other user in the first place.
Heres an example. On my system the account leonardr has UID 1000. When run as root, this code will create one directory owned by root and one owned by leonardr:
Dir.mkdir("as_root") Process.as_uid(1000) do Dir.mkdir("as_leonardr") %x{whoami} end # => "leonardr "
Here are the directories:
$ ls -ld as_* drwxr-xr-x 2 leonardr root 4096 Feb 2 13:06 as_leonardr/ drwxr-xr-x 2 root root 4096 Feb 2 13:06 as_root/
When you e impersonating another user, your permissions are restricted to what that user can do. I can remove the as_root directory as a nonroot user, because I created it as root:
Process.as_uid(1000) do Dir.rmdir("as_root") end # Errno::EPERM: Operation not permitted - as_root Dir.rmdir("as_root") # => 0
On Windows, you can do something like this by splitting your Ruby script into two, and running the second one through runas.exe:
# script_one.rb system unas /user:frednerk ruby script_two.rb
Strings
Numbers
Date and Time
Arrays
Hashes
Files and Directories
Code Blocks and Iteration
Objects and Classes8
Modules and Namespaces
Reflection and Metaprogramming
XML and HTML
Graphics and Other File Formats
Databases and Persistence
Internet Services
Web Development Ruby on Rails
Web Services and Distributed Programming
Testing, Debugging, Optimizing, and Documenting
Packaging and Distributing Software
Automating Tasks with Rake
Multitasking and Multithreading
User Interface
Extending Ruby with Other Languages
System Administration