mixlib-shellout 3.1.2-universal-mingw32 → 3.2.2-universal-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mixlib/shellout.rb +5 -5
- data/lib/mixlib/shellout/helper.rb +3 -3
- data/lib/mixlib/shellout/unix.rb +3 -3
- data/lib/mixlib/shellout/version.rb +1 -1
- data/lib/mixlib/shellout/windows.rb +6 -10
- data/lib/mixlib/shellout/windows/core_ext.rb +107 -12
- 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: 663e0247dba381f59fa51b3cb0fe98716e9279573220a2b1fcef9d10047eb9d2
|
4
|
+
data.tar.gz: 9b18f4ee50ac5349ebf42fe1aae79c1551afb042546bc8240ebc7914d0e34722
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b75d76f9540016a38bfa0338a34f75869a69f64b484311c2bfd6e2e60aafa8e8108798b7f09d02735a087804590a3814f95e031b3d94e7eae1ed707b019423b
|
7
|
+
data.tar.gz: baf755c68f8d127bd24cb84e0b01102ae0a90bc6de20b3c7a053d2c6bf112600892a8d49562db3998ca91468e110f2e5dac598d34bbf2e1dc0bb02d9ec92723c
|
data/lib/mixlib/shellout.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#--
|
2
2
|
# Author:: Daniel DeLeo (<dan@chef.io>)
|
3
|
-
# Copyright:: Copyright (c)
|
3
|
+
# Copyright:: Copyright (c) Chef Software Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -16,8 +16,8 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
require "etc"
|
20
|
-
require "tmpdir"
|
19
|
+
require "etc" unless defined?(Etc)
|
20
|
+
require "tmpdir" unless defined?(Dir.mktmpdir)
|
21
21
|
require "fcntl"
|
22
22
|
require_relative "shellout/exceptions"
|
23
23
|
|
@@ -122,7 +122,7 @@ module Mixlib
|
|
122
122
|
# === Options:
|
123
123
|
# If the last argument is a Hash, it is removed from the list of args passed
|
124
124
|
# to exec and used as an options hash. The following options are available:
|
125
|
-
# * +user+: the user the
|
125
|
+
# * +user+: the user the command should run as. if an integer is given, it is
|
126
126
|
# used as a uid. A string is treated as a username and resolved to a uid
|
127
127
|
# with Etc.getpwnam
|
128
128
|
# * +group+: the group the command should run as. works similarly to +user+
|
@@ -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&.exitstatus
|
252
252
|
end
|
253
253
|
|
254
254
|
# Run the command, writing the command's standard out and standard error
|
@@ -16,7 +16,7 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
18
|
require_relative "../shellout"
|
19
|
-
require "chef-utils"
|
19
|
+
require "chef-utils" unless defined?(ChefUtils)
|
20
20
|
require "chef-utils/dsl/default_paths"
|
21
21
|
require "chef-utils/internal"
|
22
22
|
|
@@ -30,7 +30,7 @@ module Mixlib
|
|
30
30
|
# These APIs are considered public for use in ohai and chef (by cookbooks and plugins, etc)
|
31
31
|
# but are considered private/experimental for now for the direct users of mixlib-shellout.
|
32
32
|
#
|
33
|
-
# You can see an example of how to handle the "
|
33
|
+
# You can see an example of how to handle the "dependency injection" in the rspec unit test.
|
34
34
|
# That backend API is left deliberately undocumented for now and may not follow SemVer and may
|
35
35
|
# break at any time (at least for the rest of 2020).
|
36
36
|
#
|
@@ -157,7 +157,7 @@ module Mixlib
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def __io_for_live_stream
|
160
|
-
if STDOUT.
|
160
|
+
if !STDOUT.closed? && __log.trace?
|
161
161
|
STDOUT
|
162
162
|
else
|
163
163
|
nil
|
data/lib/mixlib/shellout/unix.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Daniel DeLeo (<dan@chef.io>)
|
3
|
-
# Copyright:: Copyright (c)
|
3
|
+
# Copyright:: Copyright (c) Chef Software Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -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")
|
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")
|
378
378
|
Process.kill(:KILL, child_pgid)
|
379
379
|
reap
|
380
380
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# Author:: Daniel DeLeo (<dan@chef.io>)
|
3
3
|
# Author:: John Keiser (<jkeiser@chef.io>)
|
4
4
|
# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
|
5
|
-
# Copyright:: Copyright (c)
|
5
|
+
# Copyright:: Copyright (c) Chef Software Inc.
|
6
6
|
# License:: Apache License, Version 2.0
|
7
7
|
#
|
8
8
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -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))
|
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}")
|
128
128
|
end
|
129
129
|
|
130
130
|
raise Mixlib::ShellOut::CommandTimeout, [
|
@@ -208,7 +208,7 @@ module Mixlib
|
|
208
208
|
# 4. if the argument must be quoted by #1 and terminates in a sequence of backslashes then all the backlashes must themselves
|
209
209
|
# be backslash excaped (double the backslashes).
|
210
210
|
# 5. if an interior quote that must be escaped by #2 has a sequence of backslashes before it then all the backslashes must
|
211
|
-
# themselves be backslash excaped along with the backslash
|
211
|
+
# themselves be backslash excaped along with the backslash escape of the interior quote (double plus one backslashes).
|
212
212
|
#
|
213
213
|
# And to restate. We are constructing a string which will be parsed by the windows parser into arguments, and we want those
|
214
214
|
# arguments to match the *args array we are passed here. So call the windows parser operation A then we need to apply A^-1 to
|
@@ -398,20 +398,16 @@ module Mixlib
|
|
398
398
|
|
399
399
|
def kill_process(instance, logger)
|
400
400
|
child_pid = instance.wmi_ole_object.processid
|
401
|
-
|
402
|
-
logger.debug([
|
401
|
+
logger&.debug([
|
403
402
|
"killing child process #{child_pid}::",
|
404
403
|
"#{instance.wmi_ole_object.Name} of parent #{pid}",
|
405
404
|
].join)
|
406
|
-
end
|
407
405
|
Process.kill(:KILL, instance.wmi_ole_object.processid)
|
408
406
|
rescue SystemCallError
|
409
|
-
|
410
|
-
logger.debug([
|
407
|
+
logger&.debug([
|
411
408
|
"Failed to kill child process #{child_pid}::",
|
412
409
|
"#{instance.wmi_ole_object.Name} of parent #{pid}",
|
413
410
|
].join)
|
414
|
-
end
|
415
411
|
end
|
416
412
|
|
417
413
|
def format_process(process, app_name, command_line, timeout)
|
@@ -1,7 +1,7 @@
|
|
1
|
-
|
1
|
+
#
|
2
2
|
# Author:: Daniel DeLeo (<dan@chef.io>)
|
3
3
|
# Author:: John Keiser (<jkeiser@chef.io>)
|
4
|
-
# Copyright:: Copyright (c)
|
4
|
+
# Copyright:: Copyright (c) Chef Software Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -18,10 +18,10 @@
|
|
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
|
24
|
-
private
|
25
25
|
|
26
26
|
LOGON32_LOGON_INTERACTIVE = 0x00000002
|
27
27
|
LOGON32_LOGON_BATCH = 0x00000004
|
@@ -45,6 +45,8 @@ module Process::Constants
|
|
45
45
|
WIN32_PROFILETYPE_PT_MANDATORY = 0x04
|
46
46
|
WIN32_PROFILETYPE_PT_ROAMING_PREEXISTING = 0x08
|
47
47
|
|
48
|
+
# The environment block list ends with two nulls (\0\0).
|
49
|
+
ENVIRONMENT_BLOCK_ENDS = "\0\0".freeze
|
48
50
|
end
|
49
51
|
|
50
52
|
# Structs required for data handling
|
@@ -78,6 +80,12 @@ module Process::Functions
|
|
78
80
|
attach_pfunc :UnloadUserProfile,
|
79
81
|
%i{handle handle}, :bool
|
80
82
|
|
83
|
+
attach_pfunc :CreateEnvironmentBlock,
|
84
|
+
%i{pointer ulong bool}, :bool
|
85
|
+
|
86
|
+
attach_pfunc :DestroyEnvironmentBlock,
|
87
|
+
%i{pointer}, :bool
|
88
|
+
|
81
89
|
ffi_lib :advapi32
|
82
90
|
|
83
91
|
attach_pfunc :LogonUserW,
|
@@ -148,15 +156,13 @@ module Process
|
|
148
156
|
si_hash = {}
|
149
157
|
|
150
158
|
# If the startup_info key is present, validate its subkeys
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
raise ArgumentError, "invalid startup_info key '#{key}'"
|
156
|
-
end
|
157
|
-
|
158
|
-
si_hash[key] = val
|
159
|
+
hash["startup_info"]&.each do |key, val|
|
160
|
+
key = key.to_s.downcase
|
161
|
+
unless valid_si_keys.include?(key)
|
162
|
+
raise ArgumentError, "invalid startup_info key '#{key}'"
|
159
163
|
end
|
164
|
+
|
165
|
+
si_hash[key] = val
|
160
166
|
end
|
161
167
|
|
162
168
|
# The +command_line+ key is mandatory unless the +app_name+ key
|
@@ -172,9 +178,25 @@ module Process
|
|
172
178
|
|
173
179
|
env = nil
|
174
180
|
|
181
|
+
# Retrieve the environment variables for the specified user.
|
182
|
+
if hash["with_logon"]
|
183
|
+
logon, passwd, domain = format_creds_from_hash(hash)
|
184
|
+
logon_type = hash["elevated"] ? LOGON32_LOGON_BATCH : LOGON32_LOGON_INTERACTIVE
|
185
|
+
token = logon_user(logon, domain, passwd, logon_type)
|
186
|
+
logon_ptr = FFI::MemoryPointer.from_string(logon)
|
187
|
+
profile = PROFILEINFO.new.tap do |dat|
|
188
|
+
dat[:dwSize] = dat.size
|
189
|
+
dat[:dwFlags] = 1
|
190
|
+
dat[:lpUserName] = logon_ptr
|
191
|
+
end
|
192
|
+
|
193
|
+
load_user_profile(token, profile.pointer)
|
194
|
+
env_list = retrieve_environment_variables(token)
|
195
|
+
end
|
196
|
+
|
175
197
|
# The env string should be passed as a string of ';' separated paths.
|
176
198
|
if hash["environment"]
|
177
|
-
env = hash["environment"]
|
199
|
+
env = env_list.nil? ? hash["environment"] : merge_env_variables(env_list, hash["environment"])
|
178
200
|
|
179
201
|
unless env.respond_to?(:join)
|
180
202
|
env = hash["environment"].split(File::PATH_SEPARATOR)
|
@@ -396,6 +418,33 @@ module Process
|
|
396
418
|
true
|
397
419
|
end
|
398
420
|
|
421
|
+
# Retrieves the environment variables for the specified user.
|
422
|
+
#
|
423
|
+
# @param env_pointer [Pointer] The environment block is an array of null-terminated Unicode strings.
|
424
|
+
# @param token [Integer] User token handle.
|
425
|
+
# @return [Boolean] true if successfully retrieves the environment variables for the specified user.
|
426
|
+
#
|
427
|
+
def create_environment_block(env_pointer, token)
|
428
|
+
unless CreateEnvironmentBlock(env_pointer, token, false)
|
429
|
+
raise SystemCallError.new("CreateEnvironmentBlock", FFI.errno)
|
430
|
+
end
|
431
|
+
|
432
|
+
true
|
433
|
+
end
|
434
|
+
|
435
|
+
# Frees environment variables created by the CreateEnvironmentBlock function.
|
436
|
+
#
|
437
|
+
# @param env_pointer [Pointer] The environment block is an array of null-terminated Unicode strings.
|
438
|
+
# @return [Boolean] true if successfully frees environment variables created by the CreateEnvironmentBlock function.
|
439
|
+
#
|
440
|
+
def destroy_environment_block(env_pointer)
|
441
|
+
unless DestroyEnvironmentBlock(env_pointer)
|
442
|
+
raise SystemCallError.new("DestroyEnvironmentBlock", FFI.errno)
|
443
|
+
end
|
444
|
+
|
445
|
+
true
|
446
|
+
end
|
447
|
+
|
399
448
|
def create_process_as_user(token, app, cmd, process_security,
|
400
449
|
thread_security, inherit, creation_flags, env, cwd, startinfo, procinfo)
|
401
450
|
|
@@ -530,5 +579,51 @@ module Process
|
|
530
579
|
[ logon, passwd, domain ]
|
531
580
|
end
|
532
581
|
|
582
|
+
# Retrieves the environment variables for the specified user.
|
583
|
+
#
|
584
|
+
# @param token [Integer] User token handle.
|
585
|
+
# @return env_list [Array<String>] Environment variables of specified user.
|
586
|
+
#
|
587
|
+
def retrieve_environment_variables(token)
|
588
|
+
env_list = []
|
589
|
+
env_pointer = FFI::MemoryPointer.new(:pointer)
|
590
|
+
create_environment_block(env_pointer, token)
|
591
|
+
str_ptr = env_pointer.read_pointer
|
592
|
+
offset = 0
|
593
|
+
loop do
|
594
|
+
new_str_pointer = str_ptr + offset
|
595
|
+
break if new_str_pointer.read_string(2) == ENVIRONMENT_BLOCK_ENDS
|
596
|
+
|
597
|
+
environment = new_str_pointer.read_wstring
|
598
|
+
env_list << environment
|
599
|
+
offset = offset + environment.length * 2 + 2
|
600
|
+
end
|
601
|
+
|
602
|
+
# To free the buffer when we have finished with the environment block
|
603
|
+
destroy_environment_block(str_ptr)
|
604
|
+
env_list
|
605
|
+
end
|
606
|
+
|
607
|
+
# Merge environment variables of specified user and current environment variables.
|
608
|
+
#
|
609
|
+
# @param fetched_env [Array<String>] environment variables of specified user.
|
610
|
+
# @param current_env [Array<String>] current environment variables.
|
611
|
+
# @return [Array<String>] Merged environment variables.
|
612
|
+
#
|
613
|
+
def merge_env_variables(fetched_env, current_env)
|
614
|
+
env_hash_1 = environment_list_to_hash(fetched_env)
|
615
|
+
env_hash_2 = environment_list_to_hash(current_env)
|
616
|
+
merged_env = env_hash_2.merge(env_hash_1)
|
617
|
+
merged_env.map { |k, v| "#{k}=#{v}" }
|
618
|
+
end
|
619
|
+
|
620
|
+
# Convert an array to a hash.
|
621
|
+
#
|
622
|
+
# @param env_var [Array<String>] Environment variables.
|
623
|
+
# @return [Hash] Converted an array to hash.
|
624
|
+
#
|
625
|
+
def environment_list_to_hash(env_var)
|
626
|
+
Hash[ env_var.map { |pair| pair.split("=", 2) } ]
|
627
|
+
end
|
533
628
|
end
|
534
629
|
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.2
|
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-16 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: 0.
|
33
|
+
version: '0.9'
|
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: 0.
|
40
|
+
version: '0.9'
|
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: []
|