2014-03-16 17:59:18 +00:00
|
|
|
require 'tempfile'
|
|
|
|
|
|
|
|
module Vagrant
|
|
|
|
module LXC
|
|
|
|
module Command
|
|
|
|
class Sudoers < Vagrant.plugin("2", :command)
|
2014-04-08 17:58:07 +00:00
|
|
|
|
|
|
|
def initialize(argv, env)
|
|
|
|
super
|
|
|
|
@env = env
|
|
|
|
end
|
|
|
|
|
2014-03-16 17:59:18 +00:00
|
|
|
def execute
|
2014-03-21 22:48:34 +00:00
|
|
|
options = { user: ENV['USER'] }
|
2014-03-16 17:59:18 +00:00
|
|
|
|
|
|
|
opts = OptionParser.new do |opts|
|
|
|
|
opts.banner = "Usage: vagrant lxc sudoers"
|
|
|
|
opts.separator ""
|
2014-03-21 22:53:49 +00:00
|
|
|
opts.on('-u', '--user', "The user for which to create the policy (defaults to '#{options[:user]}')") do |u|
|
|
|
|
options[:user] = u
|
2014-03-16 17:59:18 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
argv = parse_options(opts)
|
|
|
|
return unless argv
|
|
|
|
|
2014-04-08 17:58:07 +00:00
|
|
|
wrapper_path = Vagrant::LXC.sudo_wrapper_path
|
|
|
|
wrapper = create_wrapper!
|
|
|
|
sudoers = create_sudoers!(options[:user], wrapper_path)
|
|
|
|
|
|
|
|
su_copy([
|
|
|
|
{source: wrapper, target: wrapper_path, mode: "0555"},
|
|
|
|
{source: sudoers, target: sudoers_path, mode: "0440"}
|
|
|
|
])
|
|
|
|
end
|
|
|
|
|
|
|
|
def sudoers_path
|
|
|
|
"/etc/sudoers.d/vagrant-lxc-#{Vagrant::LXC::VERSION.gsub( /\./, '-')}"
|
2014-03-16 17:59:18 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2014-04-08 17:58:07 +00:00
|
|
|
# REFACTOR: Make use ERB rendering after https://github.com/mitchellh/vagrant/issues/3231
|
|
|
|
# lands into core
|
|
|
|
def create_wrapper!
|
|
|
|
wrapper = Tempfile.new('lxc-wrapper').tap do |file|
|
|
|
|
file.puts "#!/usr/bin/env ruby"
|
|
|
|
file.puts "# Automatically created by vagrant-lxc"
|
|
|
|
file.puts <<-EOF
|
|
|
|
class Whitelist
|
|
|
|
class << self
|
|
|
|
def add(command, *args)
|
|
|
|
list[command] << args
|
|
|
|
end
|
|
|
|
|
|
|
|
def list
|
|
|
|
@list ||= Hash.new do |key, hsh|
|
|
|
|
key[hsh] = []
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def allowed(command)
|
|
|
|
list[command] || []
|
|
|
|
end
|
|
|
|
|
|
|
|
def run!(argv)
|
|
|
|
begin
|
|
|
|
command, args = `which \#{argv.shift}`.chomp, argv || []
|
|
|
|
check!(command, args)
|
|
|
|
puts `\#{command} \#{args.join(" ")}`
|
|
|
|
exit $?.to_i
|
|
|
|
rescue => e
|
|
|
|
STDERR.puts e.message
|
|
|
|
exit 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
def check!(command, args)
|
|
|
|
allowed(command).each do |checks|
|
|
|
|
return if valid_args?(args, checks)
|
|
|
|
end
|
|
|
|
raise_invalid(command, args)
|
|
|
|
end
|
|
|
|
|
|
|
|
def valid_args?(args, checks)
|
|
|
|
return false unless valid_length?(args, checks)
|
|
|
|
check = nil
|
|
|
|
args.each_with_index do |provided, i|
|
|
|
|
check = checks[i] unless check == '**'
|
|
|
|
return false unless match?(provided, check)
|
|
|
|
end
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def valid_length?(args, checks)
|
|
|
|
args.length == checks.length || checks.last == '**'
|
|
|
|
end
|
|
|
|
|
|
|
|
def match?(arg, check)
|
|
|
|
check == '**' || check.is_a?(Regexp) && !!check.match(arg) || arg == check
|
|
|
|
end
|
|
|
|
|
|
|
|
def raise_invalid(command, args)
|
|
|
|
raise "Invalid arguments for command \#{command}, " <<
|
|
|
|
"provided args: \#{args.inspect}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
base = "/var/lib/lxc"
|
|
|
|
base_path = %r{\\A\#{base}/.*\\z}
|
|
|
|
templates_path = %r{\\A/usr/(share|lib|lib64|local/lib)/lxc/templates/.*\\z}
|
|
|
|
boxes_path = %r{\\A#{Regexp.escape(@env.boxes_path.to_s)}/.*\\z}
|
|
|
|
gems_path = %r{\\A#{Regexp.escape(@env.gems_path.to_s)}/.*\\z}
|
|
|
|
template_src = %r{\\A#{Vagrant::LXC.source_root.join('scripts/lxc-template').to_s}\\z}
|
|
|
|
|
|
|
|
##
|
|
|
|
# Commands from provider.rb
|
|
|
|
# - Check lxc is installed
|
|
|
|
Whitelist.add '/usr/bin/which', /\\Alxc-\\w+\\z/
|
|
|
|
|
|
|
|
##
|
|
|
|
# Commands from driver.rb
|
|
|
|
# - Container config file
|
|
|
|
Whitelist.add '/bin/cat', base_path
|
|
|
|
# - Shared folders
|
|
|
|
Whitelist.add '/bin/mkdir', '-p', base_path
|
|
|
|
# - Container config customizations and pruning
|
2014-04-17 10:56:56 +00:00
|
|
|
Whitelist.add '/bin/cp', '-f', %r{/tmp/.*}, base_path
|
|
|
|
Whitelist.add '/bin/chown', 'root:root', base_path
|
2014-04-08 17:58:07 +00:00
|
|
|
# - Template import
|
|
|
|
Whitelist.add '/bin/cp', boxes_path, templates_path
|
|
|
|
Whitelist.add '/bin/cp', gems_path, templates_path
|
|
|
|
Whitelist.add '/bin/cp', template_src, templates_path
|
|
|
|
Whitelist.add '/bin/chmod', '+x', templates_path
|
|
|
|
# - Template removal
|
|
|
|
Whitelist.add '/bin/rm', templates_path
|
|
|
|
# - Packaging
|
2014-04-17 10:56:56 +00:00
|
|
|
Whitelist.add '/bin/tar', '--numeric-owner', '-cvzf', %r{/tmp/.*/rootfs.tar.gz}, '-C', base_path, './rootfs'
|
2014-04-08 17:58:07 +00:00
|
|
|
Whitelist.add '/bin/chown', /\\A\\d+:\\d+\\z/, %r{\\A/tmp/.*/rootfs\.tar\.gz\\z}
|
|
|
|
|
|
|
|
##
|
|
|
|
# Commands from driver/cli.rb
|
|
|
|
Whitelist.add '/usr/bin/lxc-version'
|
|
|
|
Whitelist.add '/usr/bin/lxc-ls'
|
|
|
|
Whitelist.add '/usr/bin/lxc-info', '--name', /.*/
|
|
|
|
Whitelist.add '/usr/bin/lxc-create', '--template', /.*/, '--name', /.*/, '**'
|
|
|
|
Whitelist.add '/usr/bin/lxc-destroy', '--name', /.*/
|
|
|
|
Whitelist.add '/usr/bin/lxc-start', '-d', '--name', /.*/, '**'
|
|
|
|
Whitelist.add '/usr/bin/lxc-stop', '--name', /.*/
|
|
|
|
Whitelist.add '/usr/bin/lxc-shutdown', '--name', /.*/
|
|
|
|
Whitelist.add '/usr/bin/lxc-attach', '--name', /.*/, '**'
|
|
|
|
Whitelist.add '/usr/bin/lxc-attach', '-h'
|
|
|
|
|
|
|
|
##
|
|
|
|
# Commands from driver/action/remove_temporary_files.rb
|
|
|
|
Whitelist.add '/bin/rm', '-rf', %r{\\A\#{base}/.*/rootfs/tmp/.*}
|
|
|
|
|
|
|
|
# Watch out for stones
|
|
|
|
Whitelist.run!(ARGV)
|
|
|
|
EOF
|
|
|
|
end
|
|
|
|
wrapper.close
|
|
|
|
wrapper.path
|
|
|
|
end
|
2014-03-21 22:53:49 +00:00
|
|
|
|
|
|
|
# REFACTOR: Make use ERB rendering after https://github.com/mitchellh/vagrant/issues/3231
|
|
|
|
# lands into core
|
2014-04-08 17:58:07 +00:00
|
|
|
def create_sudoers!(user, command)
|
|
|
|
sudoers = Tempfile.new('vagrant-lxc-sudoers').tap do |file|
|
|
|
|
file.puts "# Automatically created by vagrant-lxc"
|
|
|
|
file.puts "Cmnd_Alias LXC = #{command}"
|
|
|
|
file.puts "#{user} ALL=(root) NOPASSWD: LXC"
|
2014-03-16 17:59:18 +00:00
|
|
|
end
|
|
|
|
sudoers.close
|
|
|
|
sudoers.path
|
|
|
|
end
|
|
|
|
|
2014-04-08 17:58:07 +00:00
|
|
|
def su_copy(files)
|
|
|
|
commands = files.map { |file|
|
|
|
|
[
|
|
|
|
"rm -f #{file[:target]}",
|
|
|
|
"cp #{file[:source]} #{file[:target]}",
|
|
|
|
"chown root:root #{file[:target]}",
|
|
|
|
"chmod #{file[:mode]} #{file[:target]}"
|
|
|
|
]
|
|
|
|
}.flatten
|
|
|
|
system "echo \"#{commands.join("; ")}\" | sudo sh"
|
2014-03-16 17:59:18 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|