diff options
author | Nitz <nitz.raz@gmail.com> | 2015-02-15 11:34:16 +0200 |
---|---|---|
committer | Nitz <nitz.raz@gmail.com> | 2015-02-15 12:02:58 +0200 |
commit | acfc87c4a38ff7c6fa8a33e53308010a74a0d5ce (patch) | |
tree | 80e1909bafb40acaa6b19d409ec201c85040c16f /lib/mixlib | |
parent | 77211bdafb783b9067aa1fb32cd8bfa026a9769f (diff) | |
download | mixlib-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.rb | 17 | ||||
-rw-r--r-- | lib/mixlib/shellout/unix.rb | 51 |
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 |