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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92c5afe3e5855d00509b4572c17660939c989f18f78ac3a10c37557e4aee0c41
4
- data.tar.gz: 6fe34230ee29d956efa30c718597836ef620ef5d0f6814fa7cf5f0c661796827
3
+ metadata.gz: 00f4730aaa3fe480f46217bfe963ebe9ca037f42a416ed437ae652ad01546991
4
+ data.tar.gz: 639bd615824b4f8b5c06e00f092f352f8e8bff6b6f6d58cb38926bccd82dc3bb
5
5
  SHA512:
6
- metadata.gz: b3b54ec98167f6206ff1f9d7448fb8884681bcc7196efca871fea743f75c2caea2860c893f235a190b5c38ce8fa66550a498f7450052884884f31d76fba5529f
7
- data.tar.gz: 84773efd97d6e2f5b092d6209f041f3c7c9c72de9b946f39b9205c95e184f9e40ccda86fd6bb121d082539a7efb0468e424f77401922e72a51b10910d1ec96f1
6
+ metadata.gz: 43abff4b66af104549f91ae03bd29bbd571b05a5795139fe38896773e9a966fb70bc4214b920ae3ccb7984164e55099205fa50ee105c96c570cb041be84ea396
7
+ data.tar.gz: 729981e52f21ddb356a4d530eaabc958502ca2d81c844285050eb7a1808d4f841784b25db072bfb36904daecef9d4bfc40056bb295b8634c4cd9b58fc83b7aaf
@@ -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&.exitstatus
251
+ @status && @status.exitstatus
252
252
  end
253
253
 
254
254
  # Run the command, writing the command's standard out and standard error
@@ -157,7 +157,7 @@ module Mixlib
157
157
  end
158
158
 
159
159
  def __io_for_live_stream
160
- if !STDOUT.closed? && __log.trace?
160
+ if STDOUT.tty? && !__config[:daemon] && __log.debug?
161
161
  STDOUT
162
162
  else
163
163
  nil
@@ -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&.error("Command exceeded allowed execution time, sending TERM")
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&.error("Command exceeded allowed execution time, sending KILL")
377
+ logger.error("Command exceeded allowed execution time, sending KILL") if logger
378
378
  Process.kill(:KILL, child_pgid)
379
379
  reap
380
380
 
@@ -1,5 +1,5 @@
1
1
  module Mixlib
2
2
  class ShellOut
3
- VERSION = "3.1.7".freeze
3
+ VERSION = "3.2.0".freeze
4
4
  end
5
5
  end
@@ -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&.debug(format_process(process, app_name, command_line, timeout))
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&.warn("Failed to kill timed out process #{process.process_id}")
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&.debug([
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&.debug([
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"]&.each do |key, val|
151
- key = key.to_s.downcase
152
- unless valid_si_keys.include?(key)
153
- raise ArgumentError, "invalid startup_info key '#{key}'"
154
- end
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
- si_hash[key] = val
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.1.7
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-10-29 00:00:00.000000000 Z
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: '0.9'
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: '0.9'
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: []