mixlib-shellout 3.1.1-universal-mingw32 → 3.2.0-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 +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: []
|