summaryrefslogtreecommitdiff
path: root/lib/mixlib
diff options
context:
space:
mode:
authorNitz <nitz.raz@gmail.com>2015-02-15 11:34:16 +0200
committerNitz <nitz.raz@gmail.com>2015-02-15 12:02:58 +0200
commitacfc87c4a38ff7c6fa8a33e53308010a74a0d5ce (patch)
tree80e1909bafb40acaa6b19d409ec201c85040c16f /lib/mixlib
parent77211bdafb783b9067aa1fb32cd8bfa026a9769f (diff)
downloadmixlib-shellout-acfc87c4a38ff7c6fa8a33e53308010a74a0d5ce.tar.gz
Option "login" now simulates login in unix
Added: * Secondary groups from etc files * Set environment variables like `su` would * Set primary group to user's primary group if no other group specified All only if `login` is set
Diffstat (limited to 'lib/mixlib')
-rw-r--r--lib/mixlib/shellout.rb17
-rw-r--r--lib/mixlib/shellout/unix.rb51
2 files changed, 64 insertions, 4 deletions
diff --git a/lib/mixlib/shellout.rb b/lib/mixlib/shellout.rb
index e0fb3cc..3b7bf24 100644
--- a/lib/mixlib/shellout.rb
+++ b/lib/mixlib/shellout.rb
@@ -42,6 +42,10 @@ module Mixlib
attr_accessor :password
attr_accessor :with_logon
+ # Whether to simulate logon as the user. Normally set via options passed to new
+ # Always enabled on windows
+ attr_accessor :login
+
# Group the command will run as. Normally set via options passed to new
attr_accessor :group
@@ -141,6 +145,8 @@ module Mixlib
# child process. Generally this is used to copy data from the child to
# the parent's stdout so that users may observe the progress of
# long-running commands.
+ # * +login+: Whether to simulate a login (set secondary groups, primary group, environment
+ # variables etc) as done by the OS in an actual login
# === Examples:
# Invoke find(1) to search for .rb files:
# find = Mixlib::ShellOut.new("find . -name '*.rb'")
@@ -200,8 +206,9 @@ module Mixlib
# The gid that the subprocess will switch to. If the group attribute is
# given as a group name, it is converted to a gid by Etc.getgrnam
def gid
- return nil unless group
- group.kind_of?(Integer) ? group : Etc.getgrnam(group.to_s).gid
+ return group.kind_of?(Integer) ? group : Etc.getgrnam(group.to_s).gid if group
+ return Etc.getpwuid(uid).gid if using_login?
+ return nil
end
def timeout
@@ -322,7 +329,8 @@ module Mixlib
self.log_tag = setting
when 'environment', 'env'
self.environment = setting || {}
-
+ when 'login'
+ self.login = setting
else
raise InvalidCommandOption, "option '#{option.inspect}' is not a valid option for #{self.class.name}"
end
@@ -332,6 +340,9 @@ module Mixlib
end
def validate_options(opts)
+ if login && !user
+ raise InvalidCommandOption, "cannot set login without specifying a user"
+ end
super
end
end
diff --git a/lib/mixlib/shellout/unix.rb b/lib/mixlib/shellout/unix.rb
index 40d7efa..d8063df 100644
--- a/lib/mixlib/shellout/unix.rb
+++ b/lib/mixlib/shellout/unix.rb
@@ -30,6 +30,47 @@ module Mixlib
# No options to validate, raise exceptions here if needed
end
+ # Whether we're simulating a login shell
+ def using_login?
+ return login && user
+ end
+
+ # Helper method for sgids
+ def all_seconderies
+ ret = []
+ Etc.endgrent
+ while ( g = Etc.getgrent ) do
+ ret << g
+ end
+ Etc.endgrent
+ return ret
+ end
+
+ # The secondary groups that the subprocess will switch to.
+ # Currently valid only if login is used, and is set
+ # to the user's secondary groups
+ def sgids
+ return nil unless using_login?
+ user_name = Etc.getpwuid(uid).name
+ all_seconderies.select{|g| g.mem.include?(user_name)}.map{|g|g.gid}
+ end
+
+ # The environment variables that are deduced from simulating logon
+ # Only valid if login is used
+ def logon_environment
+ return {} unless using_login?
+ entry = Etc.getpwuid(uid)
+ # According to `man su`, the set fields are:
+ # $HOME, $SHELL, $USER, $LOGNAME, $PATH, and $IFS
+ # Values are copied from "shadow" package in Ubuntu 14.10
+ {'HOME'=>entry.dir, 'SHELL'=>entry.shell, 'USER'=>entry.name, 'LOGNAME'=>entry.name, 'PATH'=>'/sbin:/bin:/usr/sbin:/usr/bin', 'IFS'=>"\t\n"}
+ end
+
+ # Merges the two environments for the process
+ def process_environment
+ logon_environment.merge(self.environment)
+ end
+
# Run the command, writing the command's standard out and standard error
# to +stdout+ and +stderr+, and saving its exit status object to +status+
# === Returns
@@ -133,8 +174,15 @@ module Mixlib
end
end
+ def set_secondarygroups
+ if sgids
+ Process.groups = sgids
+ end
+ end
+
def set_environment
- environment.each do |env_var,value|
+ # user-set variables should override the login ones
+ process_environment.each do |env_var,value|
ENV[env_var] = value
end
end
@@ -295,6 +343,7 @@ module Mixlib
configure_subprocess_file_descriptors
+ set_secondarygroups
set_group
set_user
set_environment