sudo: explicitly specify the root user where necessary

With sudoers one may override default sudo user. This mostly works
provided the admin configured the replacement appropriately. However
there are exceptions that absolutely must be run by root such as
/usr/sbin/installer and, under certain circumstances, /bin/launchctl.
This commit is contained in:
Ilya Kulakov 2023-02-14 13:24:36 -08:00
parent e191b827cc
commit 563387a7b4
4 changed files with 25 additions and 17 deletions

View File

@ -106,13 +106,14 @@ module Cask
all_services.each do |service| all_services.each do |service|
ohai "Removing launchctl service #{service}" ohai "Removing launchctl service #{service}"
booleans.each do |with_sudo| booleans.each do |with_sudo|
sudo_user = with_sudo ? "root" : ""
plist_status = command.run( plist_status = command.run(
"/bin/launchctl", "/bin/launchctl",
args: ["list", service], args: ["list", service],
sudo: with_sudo, print_stderr: false sudo: sudo_user, print_stderr: false
).stdout ).stdout
if plist_status.start_with?("{") if plist_status.start_with?("{")
command.run!("/bin/launchctl", args: ["remove", service], sudo: with_sudo) command.run!("/bin/launchctl", args: ["remove", service], sudo: sudo_user)
sleep 1 sleep 1
end end
paths = [ paths = [
@ -122,13 +123,13 @@ module Cask
paths.each { |elt| elt.prepend(Dir.home).freeze } unless with_sudo paths.each { |elt| elt.prepend(Dir.home).freeze } unless with_sudo
paths = paths.map { |elt| Pathname(elt) }.select(&:exist?) paths = paths.map { |elt| Pathname(elt) }.select(&:exist?)
paths.each do |path| paths.each do |path|
command.run!("/bin/rm", args: ["-f", "--", path], sudo: with_sudo) command.run!("/bin/rm", args: ["-f", "--", path], sudo: sudo_user)
end end
# undocumented and untested: pass a path to uninstall :launchctl # undocumented and untested: pass a path to uninstall :launchctl
next unless Pathname(service).exist? next unless Pathname(service).exist?
command.run!("/bin/launchctl", args: ["unload", "-w", "--", service], sudo: with_sudo) command.run!("/bin/launchctl", args: ["unload", "-w", "--", service], sudo: sudo_user)
command.run!("/bin/rm", args: ["-f", "--", service], sudo: with_sudo) command.run!("/bin/rm", args: ["-f", "--", service], sudo: sudo_user)
sleep 1 sleep 1
end end
end end
@ -301,14 +302,15 @@ module Cask
def uninstall_kext(*kexts, command: nil, **_) def uninstall_kext(*kexts, command: nil, **_)
kexts.each do |kext| kexts.each do |kext|
ohai "Unloading kernel extension #{kext}" ohai "Unloading kernel extension #{kext}"
is_loaded = system_command!("/usr/sbin/kextstat", args: ["-l", "-b", kext], sudo: true).stdout is_loaded = system_command!("/usr/sbin/kextstat", args: ["-l", "-b", kext], sudo: "root").stdout
if is_loaded.length > 1 if is_loaded.length > 1
system_command!("/sbin/kextunload", args: ["-b", kext], sudo: true) system_command!("/sbin/kextunload", args: ["-b", kext], sudo: "root")
sleep 1 sleep 1
end end
system_command!("/usr/sbin/kextfind", args: ["-b", kext], sudo: true).stdout.chomp.lines.each do |kext_path| kexts = system_command!("/usr/sbin/kextfind", args: ["-b", kext], sudo: "root").stdout
kexts.chomp.lines.each do |kext_path|
ohai "Removing kernel extension #{kext_path}" ohai "Removing kernel extension #{kext_path}"
system_command!("/bin/rm", args: ["-rf", kext_path], sudo: true) system_command!("/bin/rm", args: ["-rf", kext_path], sudo: "root")
end end
end end
end end

View File

@ -62,7 +62,7 @@ module Cask
"USER" => User.current, "USER" => User.current,
"USERNAME" => User.current, "USERNAME" => User.current,
} }
command.run!("/usr/sbin/installer", sudo: true, args: args, print_stdout: true, env: env) command.run!("/usr/sbin/installer", sudo: "root", args: args, print_stdout: true, env: env)
end end
end end

View File

@ -32,7 +32,7 @@ module Cask
"/usr/bin/xargs", "/usr/bin/xargs",
args: ["-0", "--", "/bin/rm", "--"], args: ["-0", "--", "/bin/rm", "--"],
input: pkgutil_bom_files.join("\0"), input: pkgutil_bom_files.join("\0"),
sudo: true, sudo: "root",
) )
end end
@ -42,7 +42,7 @@ module Cask
"/usr/bin/xargs", "/usr/bin/xargs",
args: ["-0", "--", "/bin/rm", "--"], args: ["-0", "--", "/bin/rm", "--"],
input: pkgutil_bom_specials.join("\0"), input: pkgutil_bom_specials.join("\0"),
sudo: true, sudo: "root",
) )
end end
@ -59,7 +59,7 @@ module Cask
sig { void } sig { void }
def forget def forget
odebug "Unregistering pkg receipt (aka forgetting)" odebug "Unregistering pkg receipt (aka forgetting)"
@command.run!("/usr/sbin/pkgutil", args: ["--forget", package_id], sudo: true) @command.run!("/usr/sbin/pkgutil", args: ["--forget", package_id], sudo: "root")
end end
sig { returns(T::Array[Pathname]) } sig { returns(T::Array[Pathname]) }
@ -114,7 +114,7 @@ module Cask
"/usr/bin/xargs", "/usr/bin/xargs",
args: ["-0", "--", RMDIR_SH.to_s], args: ["-0", "--", RMDIR_SH.to_s],
input: Array(path).join("\0"), input: Array(path).join("\0"),
sudo: true, sudo: "root",
) )
end end

View File

@ -64,7 +64,7 @@ class SystemCommand
params( params(
executable: T.any(String, Pathname), executable: T.any(String, Pathname),
args: T::Array[T.any(String, Integer, Float, URI::Generic)], args: T::Array[T.any(String, Integer, Float, URI::Generic)],
sudo: T::Boolean, sudo: T.any(T::Boolean, String),
env: T::Hash[String, String], env: T::Hash[String, String],
input: T.any(String, T::Array[String]), input: T.any(String, T::Array[String]),
must_succeed: T::Boolean, must_succeed: T::Boolean,
@ -122,7 +122,12 @@ class SystemCommand
attr_reader :executable, :args, :input, :chdir, :env attr_reader :executable, :args, :input, :chdir, :env
attr_predicate :sudo?, :print_stdout?, :print_stderr?, :must_succeed? attr_predicate :print_stdout?, :print_stderr?, :must_succeed?
sig { returns(T::Boolean) }
def sudo?
@sudo != false && @sudo != ""
end
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def debug? def debug?
@ -153,8 +158,9 @@ class SystemCommand
sig { returns(T::Array[String]) } sig { returns(T::Array[String]) }
def sudo_prefix def sudo_prefix
user_flags = @sudo.is_a?(String) ? ["-u", @sudo] : []
askpass_flags = ENV.key?("SUDO_ASKPASS") ? ["-A"] : [] askpass_flags = ENV.key?("SUDO_ASKPASS") ? ["-A"] : []
["/usr/bin/sudo", *askpass_flags, "-E", *env_args, "--"] ["/usr/bin/sudo", *user_flags, *askpass_flags, "-E", *env_args, "--"]
end end
sig { returns(T::Array[String]) } sig { returns(T::Array[String]) }