mixlib-shellout 3.1.1-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 +3 -3
- data/lib/mixlib/shellout/helper.rb +27 -39
- data/lib/mixlib/shellout/version.rb +1 -1
- data/lib/mixlib/shellout/windows.rb +1 -1
- data/lib/mixlib/shellout/windows/core_ext.rb +99 -1
- metadata +16 -2
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
@@ -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+
|
@@ -16,33 +16,23 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
18
|
require_relative "../shellout"
|
19
|
-
require "chef-utils"
|
20
|
-
require "chef-utils/dsl/
|
19
|
+
require "chef-utils" unless defined?(ChefUtils)
|
20
|
+
require "chef-utils/dsl/default_paths"
|
21
21
|
require "chef-utils/internal"
|
22
22
|
|
23
23
|
module Mixlib
|
24
24
|
class ShellOut
|
25
25
|
module Helper
|
26
26
|
include ChefUtils::Internal
|
27
|
-
include ChefUtils::DSL::
|
27
|
+
include ChefUtils::DSL::DefaultPaths
|
28
28
|
|
29
|
-
# PREFERRED APIS:
|
30
29
|
#
|
31
|
-
#
|
30
|
+
# These APIs are considered public for use in ohai and chef (by cookbooks and plugins, etc)
|
31
|
+
# but are considered private/experimental for now for the direct users of mixlib-shellout.
|
32
32
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
# allow(provider).to receive(:shell_out_compacted!).with("foo", "bar", "baz")
|
38
|
-
# provider.shell_out!("foo", [ "bar", nil, "baz"])
|
39
|
-
# provider.shell_out!(["foo", nil, "bar" ], ["baz"])
|
40
|
-
#
|
41
|
-
# note that shell_out_compacted also includes adding the magical timeout option to force
|
42
|
-
# people to setup expectations on that value explicitly. it does not include the default_env
|
43
|
-
# mangling in order to avoid users having to setup an expectation on anything other than
|
44
|
-
# setting `default_env: false` and allow us to make tweak to the default_env without breaking
|
45
|
-
# a thousand unit tests.
|
33
|
+
# You can see an example of how to handle the "dependency injection" in the rspec unit test.
|
34
|
+
# That backend API is left deliberately undocumented for now and may not follow SemVer and may
|
35
|
+
# break at any time (at least for the rest of 2020).
|
46
36
|
#
|
47
37
|
|
48
38
|
def shell_out(*args, **options)
|
@@ -98,15 +88,28 @@ module Mixlib
|
|
98
88
|
"LC_ALL" => __config[:internal_locale],
|
99
89
|
"LANGUAGE" => __config[:internal_locale],
|
100
90
|
"LANG" => __config[:internal_locale],
|
101
|
-
__env_path_name =>
|
91
|
+
__env_path_name => default_paths,
|
102
92
|
}.update(options[env_key] || {})
|
103
93
|
end
|
104
94
|
options
|
105
95
|
end
|
106
96
|
|
107
|
-
#
|
97
|
+
# The shell_out_compacted/shell_out_compacted! APIs are private but are intended for use
|
98
|
+
# in rspec tests. They should always be used in rspec tests instead of shell_out to allow
|
99
|
+
# for less brittle rspec tests.
|
108
100
|
#
|
109
|
-
#
|
101
|
+
# This expectation:
|
102
|
+
#
|
103
|
+
# allow(provider).to receive(:shell_out_compacted!).with("foo", "bar", "baz")
|
104
|
+
#
|
105
|
+
# Is met by many different possible calling conventions that mean the same thing:
|
106
|
+
#
|
107
|
+
# provider.shell_out!("foo", [ "bar", nil, "baz"])
|
108
|
+
# provider.shell_out!(["foo", nil, "bar" ], ["baz"])
|
109
|
+
#
|
110
|
+
# Note that when setting `default_env: false` that you should just setup an expectation on
|
111
|
+
# :shell_out_compacted for `default_env: false`, rather than the expanded env settings so
|
112
|
+
# that the default_env implementation can change without breaking unit tests.
|
110
113
|
#
|
111
114
|
def shell_out_compacted(*args, **options)
|
112
115
|
options = __apply_default_env(options)
|
@@ -117,10 +120,6 @@ module Mixlib
|
|
117
120
|
end
|
118
121
|
end
|
119
122
|
|
120
|
-
# this SHOULD be used for setting up expectations in rspec, see banner comment at top.
|
121
|
-
#
|
122
|
-
# the private constraint is meant to avoid code calling this directly, rspec expectations are fine.
|
123
|
-
#
|
124
123
|
def shell_out_compacted!(*args, **options)
|
125
124
|
options = __apply_default_env(options)
|
126
125
|
cmd = if options.empty?
|
@@ -132,23 +131,12 @@ module Mixlib
|
|
132
131
|
cmd
|
133
132
|
end
|
134
133
|
|
135
|
-
# Helper for subclasses to reject nil out of an array. It allows
|
136
|
-
#
|
137
|
-
# quote marks to deal with shells).
|
138
|
-
#
|
139
|
-
# Usage:
|
140
|
-
# shell_out!(*clean_array("useradd", universal_options, useradd_options, new_resource.username))
|
141
|
-
#
|
142
|
-
# universal_options and useradd_options can be nil, empty array, empty string, strings or arrays
|
143
|
-
# and the result makes sense.
|
144
|
-
#
|
145
|
-
# keeping this separate from shell_out!() makes it a bit easier to write expectations against the
|
146
|
-
# shell_out args and be able to omit nils and such in the tests (and to test that the nils are
|
147
|
-
# being rejected correctly).
|
134
|
+
# Helper for subclasses to reject nil out of an array. It allows using the array form of
|
135
|
+
# shell_out (which avoids the need to surround arguments with quote marks to deal with shells).
|
148
136
|
#
|
149
137
|
# @param args [String] variable number of string arguments
|
150
138
|
# @return [Array] array of strings with nil and null string rejection
|
151
|
-
|
139
|
+
#
|
152
140
|
def __clean_array(*args)
|
153
141
|
args.flatten.compact.map(&:to_s)
|
154
142
|
end
|
@@ -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
|
@@ -18,6 +18,7 @@
|
|
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
|
@@ -45,6 +46,8 @@ module Process::Constants
|
|
45
46
|
WIN32_PROFILETYPE_PT_MANDATORY = 0x04
|
46
47
|
WIN32_PROFILETYPE_PT_ROAMING_PREEXISTING = 0x08
|
47
48
|
|
49
|
+
# The environment block list ends with two nulls (\0\0).
|
50
|
+
ENVIRONMENT_BLOCK_ENDS = "\0\0".freeze
|
48
51
|
end
|
49
52
|
|
50
53
|
# Structs required for data handling
|
@@ -78,6 +81,12 @@ module Process::Functions
|
|
78
81
|
attach_pfunc :UnloadUserProfile,
|
79
82
|
%i{handle handle}, :bool
|
80
83
|
|
84
|
+
attach_pfunc :CreateEnvironmentBlock,
|
85
|
+
%i{pointer ulong bool}, :bool
|
86
|
+
|
87
|
+
attach_pfunc :DestroyEnvironmentBlock,
|
88
|
+
%i{pointer}, :bool
|
89
|
+
|
81
90
|
ffi_lib :advapi32
|
82
91
|
|
83
92
|
attach_pfunc :LogonUserW,
|
@@ -172,9 +181,25 @@ module Process
|
|
172
181
|
|
173
182
|
env = nil
|
174
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
|
+
|
175
200
|
# The env string should be passed as a string of ';' separated paths.
|
176
201
|
if hash["environment"]
|
177
|
-
env = hash["environment"]
|
202
|
+
env = env_list.nil? ? hash["environment"] : merge_env_variables(env_list, hash["environment"])
|
178
203
|
|
179
204
|
unless env.respond_to?(:join)
|
180
205
|
env = hash["environment"].split(File::PATH_SEPARATOR)
|
@@ -396,6 +421,33 @@ module Process
|
|
396
421
|
true
|
397
422
|
end
|
398
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
|
+
|
399
451
|
def create_process_as_user(token, app, cmd, process_security,
|
400
452
|
thread_security, inherit, creation_flags, env, cwd, startinfo, procinfo)
|
401
453
|
|
@@ -530,5 +582,51 @@ module Process
|
|
530
582
|
[ logon, passwd, domain ]
|
531
583
|
end
|
532
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
|
533
631
|
end
|
534
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
|
@@ -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: []
|