mixlib-shellout 3.1.7-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 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: []