diff options
author | Moser, Kevin <Kevin.Moser@nordstrom.com> | 2013-01-11 12:31:01 -0800 |
---|---|---|
committer | Moser, Kevin <Kevin.Moser@nordstrom.com> | 2013-01-11 12:31:01 -0800 |
commit | d9124ef9fa7e798b329b1dcfb86bcb6ef48f452b (patch) | |
tree | 61a0ec41661f6ae95c1921271f732f6cc4f2c630 | |
parent | 933784a3240d488cfbf79b5a9b8ecb89ef2cb44f (diff) | |
download | mixlib-shellout-d9124ef9fa7e798b329b1dcfb86bcb6ef48f452b.tar.gz |
Add process impersonation
-rw-r--r-- | lib/mixlib/shellout.rb | 11 | ||||
-rw-r--r-- | lib/mixlib/shellout/windows.rb | 5 | ||||
-rw-r--r-- | lib/mixlib/shellout/windows/core_ext.rb | 100 |
3 files changed, 89 insertions, 27 deletions
diff --git a/lib/mixlib/shellout.rb b/lib/mixlib/shellout.rb index 3b2651c..da58bac 100644 --- a/lib/mixlib/shellout.rb +++ b/lib/mixlib/shellout.rb @@ -39,6 +39,10 @@ module Mixlib # User the command will run as. Normally set via options passed to new attr_accessor :user + attr_accessor :domain + attr_accessor :password + attr_accessor :with_logon + attr_accessor :remote_call # Group the command will run as. Normally set via options passed to new attr_accessor :group @@ -261,8 +265,15 @@ module Mixlib case option.to_s when 'cwd' self.cwd = setting + when 'domain' + self.domain = setting + when 'password' + self.password = setting when 'user' self.user = setting + self.with_logon = setting + when 'remote_call' + self.remote_call = setting when 'group' self.group = setting when 'umask' diff --git a/lib/mixlib/shellout/windows.rb b/lib/mixlib/shellout/windows.rb index 7bebb3b..a8511ef 100644 --- a/lib/mixlib/shellout/windows.rb +++ b/lib/mixlib/shellout/windows.rb @@ -23,6 +23,7 @@ require 'windows/handle' require 'windows/process' require 'windows/synchronize' +require 'mixlib/shellout/windows/localsystem' require 'mixlib/shellout/windows/core_ext' module Mixlib @@ -66,6 +67,10 @@ module Mixlib :close_handles => false } create_process_args[:cwd] = cwd if cwd + create_process_args[:domain] = domain if domain + create_process_args[:with_logon] = with_logon if with_logon + create_process_args[:password] = password if password + create_process_args[:remote_call] = remote_call if remote_call # # Start the process diff --git a/lib/mixlib/shellout/windows/core_ext.rb b/lib/mixlib/shellout/windows/core_ext.rb index be25127..ca4a9af 100644 --- a/lib/mixlib/shellout/windows/core_ext.rb +++ b/lib/mixlib/shellout/windows/core_ext.rb @@ -28,6 +28,7 @@ require 'windows/synchronize' module Windows module Process API.new('CreateProcess', 'SPPPLLLPPP', 'B') + API.new('CreateProcessAsUser', 'PSPPPLLLPPP', 'B', 'advapi32.dll') end end @@ -45,7 +46,7 @@ module Process valid_keys = %w/ app_name command_line inherit creation_flags cwd environment startup_info thread_inherit process_inherit close_handles with_logon - domain password + domain password remote_call / valid_si_keys = %/ @@ -60,6 +61,9 @@ module Process 'close_handles' => true } + #See if running as local service + is_local_service = ENV["USERNAME"].downcase == "local service" + # Validate the keys, and convert symbols and case to lowercase strings. args.each{ |key, val| key = key.to_s.downcase @@ -102,10 +106,11 @@ module Process env = hash['environment'].split(File::PATH_SEPARATOR) end # The argument format is a series of null-terminated strings, with an additional null terminator. - env = env.map { |e| e + "\0" }.join("") + "\0" - if hash['with_logon'] - env = env.multi_to_wide(e) - end + # If calling CreateProcessWithLogonW must put the hash in a wide format + env = env.map do |e| + hash['with_logon'].nil? || is_local_service || hash['remote_call'] ? e + "\0" : multi_to_wide(e) + end.join("") + "\0" + env = [env].pack('p*').unpack('L').first else env = nil @@ -182,28 +187,69 @@ module Process end if hash['with_logon'] - logon = multi_to_wide(hash['with_logon']) - domain = multi_to_wide(hash['domain']) - app = hash['app_name'].nil? ? nil : multi_to_wide(hash['app_name']) - cmd = hash['command_line'].nil? ? nil : multi_to_wide(hash['command_line']) - cwd = multi_to_wide(hash['cwd']) - passwd = multi_to_wide(hash['password']) - - hash['creation_flags'] |= CREATE_UNICODE_ENVIRONMENT - - process_ran = CreateProcessWithLogonW( - logon, # User - domain, # Domain - passwd, # Password - LOGON_WITH_PROFILE, # Logon flags - app, # App name - cmd, # Command line - hash['creation_flags'], # Creation flags - env, # Environment - cwd, # Working directory - startinfo, # Startup Info - procinfo # Process Info - ) + # Need to do a LogonUser and CreateProcessAsUser to work on all windows platforms + + if is_local_service || hash['remote_call'] + include Process::Constants + extend Process::Functions + + Process.is_local_system? + + logon = hash['with_logon'] + domain = hash['domain'] + app = hash['app_name'] + cmd = hash['command_line'] + cwd = hash['cwd'] + passwd = hash['password'] + token = FFI::MemoryPointer.new(:ulong) + + LogonUser( + logon, # User + domain, # Domain + passwd, # Password + LOGON32_LOGON_INTERACTIVE, # Logon Type + LOGON32_PROVIDER_DEFAULT, # Logon Provider + token # User token handle + ) + + token = token.read_ulong + + process_ran = CreateProcessAsUser( + token, # User token handle + app, # App name + cmd, # Command line + process_security, # Process attributes + thread_security, # Thread attributes + hash['inherit'], # Inherit handles + hash['creation_flags'], # Creation Flags + env, # Environment + cwd, # Working directory + startinfo, # Startup Info + procinfo # Process Info + ) + else + logon = multi_to_wide(hash['with_logon']) + domain = multi_to_wide(hash['domain']) + app = hash['app_name'].nil? ? nil : multi_to_wide(hash['app_name']) + cmd = hash['command_line'].nil? ? nil : multi_to_wide(hash['command_line']) + cwd = multi_to_wide(hash['cwd']) + passwd = multi_to_wide(hash['password']) + hash['creation_flags'] |= CREATE_UNICODE_ENVIRONMENT + + process_ran = CreateProcessWithLogonW( + logon, # User + domain, # Domain + passwd, # Password + LOGON_WITH_PROFILE, # Logon flags + app, # App name + cmd, # Command line + hash['creation_flags'], # Creation flags + env, # Environment + cwd, # Working directory + startinfo, # Startup Info + procinfo # Process Info + ) + end else process_ran = CreateProcess( hash['app_name'], # App name |