How to create a text file in Ruby owned by root?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



How to create a text file in Ruby owned by root?



It's trivially easy in Ruby to create a text file as the current user using File.write, but if I want the file to be owned by root, it becomes a lot more complicated.


File.write



I realize that I could run the Ruby script itself with sudo but would prefer not to do that.


sudo



How can I do this?





Forget ruby for a moment -- are you able to chown root <filename>? Presumable no, you need sudo chown root <filename> (and possibly enter a password); and this will only work if you are in the sudoers file. If a ruby script - or any script for that matter - were able to bypass this security policy, then it would be a huge vulnerability in unix systems.
– Tom Lord
Aug 10 at 9:40


chown root <filename>


sudo chown root <filename>


sudoers





So one way or another, somewhere along the line you're going to need sudo permission. This could be at a the initial command line call, or invoked later on in the script, or (with extreme caution) you could set the sticky bit in the permission. But you cannot change a file owner to root without superuser permissions having been granted somewhere.
– Tom Lord
Aug 10 at 9:42



sudo


root





Yes, I realize that I need to use sudo. My point was that I did not want the entire script to be run with sudo, just the specific commands that needed it. The answer below is my own and illustrates what I mean.
– Keith Bennett
Aug 10 at 9:54


sudo




1 Answer
1



Rather than trying to create or open the file as root (which I believe is impossible if the Ruby script has been started as a nonroot user), the file can be created as the current user first and then have its ownership and permissions changed.



As a practical matter it probably makes sense to use Ruby's Tempfile functionality to create the initial file, since it eliminates the need to determine a unique filename and will not require that the current directory be writable. Here is the code I came up with (it's also posted at https://gist.github.com/keithrbennett/2c6f53351bf9cdb0bbbfd3f7f97dc91c). The module is defined and the call to it is on the last line. I've made some assumptions, e.g. that the file should be world readable:


Tempfile


#!/usr/bin/env ruby

require 'tempfile'

module SudoFileWriter

module_function

# Writes passed text to a temp file.
# @return the filespec of the temp file.
def write_to_temp_file(text)
filespec = nil
Tempfile.open do |file|
file.write(text)
filespec = file.path
end
filespec
end


def write_to_root_file(filespec, text)
temp_filespec = write_to_temp_file(text)
commands = [
"sudo chown root:wheel #temp_filespec",
"sudo mv #temp_filespec #filespec",
"sudo chmod +r #filespec"
]
puts "Running commands for file #filespec:nn"; puts commands
`#commands.join(' && ')`
end


def call(filespec, object_to_write)
write_to_root_file(filespec, object_to_write.to_s)
end
end

# .() is shorthand for .call().
# `module_function` above results in all methods being both module level
# and instance level methods, so we can call directly on the module object.

SudoFileWriter.('root-owned-file.txt', "The time is now #Time.now.n")



Output looks like this:


Running commands for file root-owned-file.txt:

sudo chown root:wheel /var/folders/bk/8y3jvjs53qs9wlqtpzqq6_080000gn/T/20180810-9981-124bxcl
sudo mv /var/folders/bk/8y3jvjs53qs9wlqtpzqq6_080000gn/T/20180810-9981-124bxcl root-owned-file.txt
sudo chmod +r root-owned-file.txt
Password:
The time is now 2018-08-10 16:01:05 +0700.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard