mixlib-shellout 3.1.7-universal-mingw32 → 3.2.0-universal-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/mixlib/shellout.rb +1 -1
- data/lib/mixlib/shellout/helper.rb +1 -1
- data/lib/mixlib/shellout/unix.rb +2 -2
- data/lib/mixlib/shellout/version.rb +1 -1
- data/lib/mixlib/shellout/windows.rb +8 -4
- data/lib/mixlib/shellout/windows/core_ext.rb +108 -7
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00f4730aaa3fe480f46217bfe963ebe9ca037f42a416ed437ae652ad01546991
|
4
|
+
data.tar.gz: 639bd615824b4f8b5c06e00f092f352f8e8bff6b6f6d58cb38926bccd82dc3bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43abff4b66af104549f91ae03bd29bbd571b05a5795139fe38896773e9a966fb70bc4214b920ae3ccb7984164e55099205fa50ee105c96c570cb041be84ea396
|
7
|
+
data.tar.gz: 729981e52f21ddb356a4d530eaabc958502ca2d81c844285050eb7a1808d4f841784b25db072bfb36904daecef9d4bfc40056bb295b8634c4cd9b58fc83b7aaf
|
data/lib/mixlib/shellout.rb
CHANGED
@@ -248,7 +248,7 @@ module Mixlib
|
|
248
248
|
# running or died without setting an exit status (e.g., terminated by
|
249
249
|
# `kill -9`).
|
250
250
|
def exitstatus
|
251
|
-
@status
|
251
|
+
@status && @status.exitstatus
|
252
252
|
end
|
253
253
|
|
254
254
|
# Run the command, writing the command's standard out and standard error
|
data/lib/mixlib/shellout/unix.rb
CHANGED
@@ -370,11 +370,11 @@ module Mixlib
|
|
370
370
|
return if attempt_reap
|
371
371
|
|
372
372
|
@terminate_reason = "Command exceeded allowed execution time, process terminated"
|
373
|
-
logger
|
373
|
+
logger.error("Command exceeded allowed execution time, sending TERM") if logger
|
374
374
|
Process.kill(:TERM, child_pgid)
|
375
375
|
sleep 3
|
376
376
|
attempt_reap
|
377
|
-
logger
|
377
|
+
logger.error("Command exceeded allowed execution time, sending KILL") if logger
|
378
378
|
Process.kill(:KILL, child_pgid)
|
379
379
|
reap
|
380
380
|
|
@@ -89,7 +89,7 @@ module Mixlib
|
|
89
89
|
# Start the process
|
90
90
|
#
|
91
91
|
process, profile, token = Process.create3(create_process_args)
|
92
|
-
logger
|
92
|
+
logger.debug(format_process(process, app_name, command_line, timeout)) if logger
|
93
93
|
begin
|
94
94
|
# Start pushing data into input
|
95
95
|
stdin_write << input if input
|
@@ -124,7 +124,7 @@ module Mixlib
|
|
124
124
|
kill_process_tree(process.process_id, wmi, logger)
|
125
125
|
Process.kill(:KILL, process.process_id)
|
126
126
|
rescue SystemCallError
|
127
|
-
logger
|
127
|
+
logger.warn("Failed to kill timed out process #{process.process_id}") if logger
|
128
128
|
end
|
129
129
|
|
130
130
|
raise Mixlib::ShellOut::CommandTimeout, [
|
@@ -398,16 +398,20 @@ module Mixlib
|
|
398
398
|
|
399
399
|
def kill_process(instance, logger)
|
400
400
|
child_pid = instance.wmi_ole_object.processid
|
401
|
-
logger
|
401
|
+
if logger
|
402
|
+
logger.debug([
|
402
403
|
"killing child process #{child_pid}::",
|
403
404
|
"#{instance.wmi_ole_object.Name} of parent #{pid}",
|
404
405
|
].join)
|
406
|
+
end
|
405
407
|
Process.kill(:KILL, instance.wmi_ole_object.processid)
|
406
408
|
rescue SystemCallError
|
407
|
-
logger
|
409
|
+
if logger
|
410
|
+
logger.debug([
|
408
411
|
"Failed to kill child process #{child_pid}::",
|
409
412
|
"#{instance.wmi_ole_object.Name} of parent #{pid}",
|
410
413
|
].join)
|
414
|
+
end
|
411
415
|
end
|
412
416
|
|
413
417
|
def format_process(process, app_name, command_line, timeout)
|
@@ -18,9 +18,11 @@
|
|
18
18
|
#
|
19
19
|
|
20
20
|
require "win32/process"
|
21
|
+
require "ffi/win32/extensions"
|
21
22
|
|
22
23
|
# Add new constants for Logon
|
23
24
|
module Process::Constants
|
25
|
+
private
|
24
26
|
|
25
27
|
LOGON32_LOGON_INTERACTIVE = 0x00000002
|
26
28
|
LOGON32_LOGON_BATCH = 0x00000004
|
@@ -44,6 +46,8 @@ module Process::Constants
|
|
44
46
|
WIN32_PROFILETYPE_PT_MANDATORY = 0x04
|
45
47
|
WIN32_PROFILETYPE_PT_ROAMING_PREEXISTING = 0x08
|
46
48
|
|
49
|
+
# The environment block list ends with two nulls (\0\0).
|
50
|
+
ENVIRONMENT_BLOCK_ENDS = "\0\0".freeze
|
47
51
|
end
|
48
52
|
|
49
53
|
# Structs required for data handling
|
@@ -77,6 +81,12 @@ module Process::Functions
|
|
77
81
|
attach_pfunc :UnloadUserProfile,
|
78
82
|
%i{handle handle}, :bool
|
79
83
|
|
84
|
+
attach_pfunc :CreateEnvironmentBlock,
|
85
|
+
%i{pointer ulong bool}, :bool
|
86
|
+
|
87
|
+
attach_pfunc :DestroyEnvironmentBlock,
|
88
|
+
%i{pointer}, :bool
|
89
|
+
|
80
90
|
ffi_lib :advapi32
|
81
91
|
|
82
92
|
attach_pfunc :LogonUserW,
|
@@ -147,13 +157,15 @@ module Process
|
|
147
157
|
si_hash = {}
|
148
158
|
|
149
159
|
# If the startup_info key is present, validate its subkeys
|
150
|
-
hash["startup_info"]
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
160
|
+
if hash["startup_info"]
|
161
|
+
hash["startup_info"].each do |key, val|
|
162
|
+
key = key.to_s.downcase
|
163
|
+
unless valid_si_keys.include?(key)
|
164
|
+
raise ArgumentError, "invalid startup_info key '#{key}'"
|
165
|
+
end
|
155
166
|
|
156
|
-
|
167
|
+
si_hash[key] = val
|
168
|
+
end
|
157
169
|
end
|
158
170
|
|
159
171
|
# The +command_line+ key is mandatory unless the +app_name+ key
|
@@ -169,9 +181,25 @@ module Process
|
|
169
181
|
|
170
182
|
env = nil
|
171
183
|
|
184
|
+
# Retrieve the environment variables for the specified user.
|
185
|
+
if hash["with_logon"]
|
186
|
+
logon, passwd, domain = format_creds_from_hash(hash)
|
187
|
+
logon_type = hash["elevated"] ? LOGON32_LOGON_BATCH : LOGON32_LOGON_INTERACTIVE
|
188
|
+
token = logon_user(logon, domain, passwd, logon_type)
|
189
|
+
logon_ptr = FFI::MemoryPointer.from_string(logon)
|
190
|
+
profile = PROFILEINFO.new.tap do |dat|
|
191
|
+
dat[:dwSize] = dat.size
|
192
|
+
dat[:dwFlags] = 1
|
193
|
+
dat[:lpUserName] = logon_ptr
|
194
|
+
end
|
195
|
+
|
196
|
+
load_user_profile(token, profile.pointer)
|
197
|
+
env_list = retrieve_environment_variables(token)
|
198
|
+
end
|
199
|
+
|
172
200
|
# The env string should be passed as a string of ';' separated paths.
|
173
201
|
if hash["environment"]
|
174
|
-
env = hash["environment"]
|
202
|
+
env = env_list.nil? ? hash["environment"] : merge_env_variables(env_list, hash["environment"])
|
175
203
|
|
176
204
|
unless env.respond_to?(:join)
|
177
205
|
env = hash["environment"].split(File::PATH_SEPARATOR)
|
@@ -393,6 +421,33 @@ module Process
|
|
393
421
|
true
|
394
422
|
end
|
395
423
|
|
424
|
+
# Retrieves the environment variables for the specified user.
|
425
|
+
#
|
426
|
+
# @param env_pointer [Pointer] The environment block is an array of null-terminated Unicode strings.
|
427
|
+
# @param token [Integer] User token handle.
|
428
|
+
# @return [Boolean] true if successfully retrieves the environment variables for the specified user.
|
429
|
+
#
|
430
|
+
def create_environment_block(env_pointer, token)
|
431
|
+
unless CreateEnvironmentBlock(env_pointer, token, false)
|
432
|
+
raise SystemCallError.new("CreateEnvironmentBlock", FFI.errno)
|
433
|
+
end
|
434
|
+
|
435
|
+
true
|
436
|
+
end
|
437
|
+
|
438
|
+
# Frees environment variables created by the CreateEnvironmentBlock function.
|
439
|
+
#
|
440
|
+
# @param env_pointer [Pointer] The environment block is an array of null-terminated Unicode strings.
|
441
|
+
# @return [Boolean] true if successfully frees environment variables created by the CreateEnvironmentBlock function.
|
442
|
+
#
|
443
|
+
def destroy_environment_block(env_pointer)
|
444
|
+
unless DestroyEnvironmentBlock(env_pointer)
|
445
|
+
raise SystemCallError.new("DestroyEnvironmentBlock", FFI.errno)
|
446
|
+
end
|
447
|
+
|
448
|
+
true
|
449
|
+
end
|
450
|
+
|
396
451
|
def create_process_as_user(token, app, cmd, process_security,
|
397
452
|
thread_security, inherit, creation_flags, env, cwd, startinfo, procinfo)
|
398
453
|
|
@@ -527,5 +582,51 @@ module Process
|
|
527
582
|
[ logon, passwd, domain ]
|
528
583
|
end
|
529
584
|
|
585
|
+
# Retrieves the environment variables for the specified user.
|
586
|
+
#
|
587
|
+
# @param token [Integer] User token handle.
|
588
|
+
# @return env_list [Array<String>] Environment variables of specified user.
|
589
|
+
#
|
590
|
+
def retrieve_environment_variables(token)
|
591
|
+
env_list = []
|
592
|
+
env_pointer = FFI::MemoryPointer.new(:pointer)
|
593
|
+
create_environment_block(env_pointer, token)
|
594
|
+
str_ptr = env_pointer.read_pointer
|
595
|
+
offset = 0
|
596
|
+
loop do
|
597
|
+
new_str_pointer = str_ptr + offset
|
598
|
+
break if new_str_pointer.read_string(2) == ENVIRONMENT_BLOCK_ENDS
|
599
|
+
|
600
|
+
environment = new_str_pointer.read_wstring
|
601
|
+
env_list << environment
|
602
|
+
offset = offset + environment.length * 2 + 2
|
603
|
+
end
|
604
|
+
|
605
|
+
# To free the buffer when we have finished with the environment block
|
606
|
+
destroy_environment_block(str_ptr)
|
607
|
+
env_list
|
608
|
+
end
|
609
|
+
|
610
|
+
# Merge environment variables of specified user and current environment variables.
|
611
|
+
#
|
612
|
+
# @param fetched_env [Array<String>] environment variables of specified user.
|
613
|
+
# @param current_env [Array<String>] current environment variables.
|
614
|
+
# @return [Array<String>] Merged environment variables.
|
615
|
+
#
|
616
|
+
def merge_env_variables(fetched_env, current_env)
|
617
|
+
env_hash_1 = environment_list_to_hash(fetched_env)
|
618
|
+
env_hash_2 = environment_list_to_hash(current_env)
|
619
|
+
merged_env = env_hash_2.merge(env_hash_1)
|
620
|
+
merged_env.map { |k, v| "#{k}=#{v}" }
|
621
|
+
end
|
622
|
+
|
623
|
+
# Convert an array to a hash.
|
624
|
+
#
|
625
|
+
# @param env_var [Array<String>] Environment variables.
|
626
|
+
# @return [Hash] Converted an array to hash.
|
627
|
+
#
|
628
|
+
def environment_list_to_hash(env_var)
|
629
|
+
Hash[ env_var.map { |pair| pair.split("=", 2) } ]
|
630
|
+
end
|
530
631
|
end
|
531
632
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mixlib-shellout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: universal-mingw32
|
6
6
|
authors:
|
7
7
|
- Chef Software Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-utils
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.8.2
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.8.2
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: wmi-lite
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: ffi-win32-extensions
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.3
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.0.3
|
55
69
|
description: Run external commands on Unix or Windows
|
56
70
|
email: info@chef.io
|
57
71
|
executables: []
|