summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoser, Kevin <Kevin.Moser@nordstrom.com>2013-01-11 12:31:01 -0800
committerMoser, Kevin <Kevin.Moser@nordstrom.com>2013-01-11 12:31:01 -0800
commitd9124ef9fa7e798b329b1dcfb86bcb6ef48f452b (patch)
tree61a0ec41661f6ae95c1921271f732f6cc4f2c630
parent933784a3240d488cfbf79b5a9b8ecb89ef2cb44f (diff)
downloadmixlib-shellout-d9124ef9fa7e798b329b1dcfb86bcb6ef48f452b.tar.gz
Add process impersonation
-rw-r--r--lib/mixlib/shellout.rb11
-rw-r--r--lib/mixlib/shellout/windows.rb5
-rw-r--r--lib/mixlib/shellout/windows/core_ext.rb100
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