puppet 6.0.5 → 6.0.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +30 -0
  3. data/Gemfile.lock +14 -14
  4. data/lib/puppet.rb +4 -4
  5. data/lib/puppet/application.rb +1 -1
  6. data/lib/puppet/application/filebucket.rb +6 -1
  7. data/lib/puppet/configurer.rb +6 -6
  8. data/lib/puppet/confine/boolean.rb +45 -0
  9. data/lib/puppet/confine/false.rb +7 -1
  10. data/lib/puppet/confine/true.rb +7 -1
  11. data/lib/puppet/defaults.rb +21 -29
  12. data/lib/puppet/functions/call.rb +2 -1
  13. data/lib/puppet/network/http/connection.rb +15 -5
  14. data/lib/puppet/pops/issues.rb +4 -0
  15. data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +60 -4
  16. data/lib/puppet/pops/model/factory.rb +38 -4
  17. data/lib/puppet/pops/parser/egrammar.ra +2 -2
  18. data/lib/puppet/pops/parser/heredoc_support.rb +17 -7
  19. data/lib/puppet/pops/parser/lexer2.rb +6 -1
  20. data/lib/puppet/pops/parser/locator.rb +106 -86
  21. data/lib/puppet/pops/parser/parser_support.rb +11 -2
  22. data/lib/puppet/pops/types/type_mismatch_describer.rb +1 -1
  23. data/lib/puppet/provider/file/windows.rb +49 -1
  24. data/lib/puppet/provider/group/windows_adsi.rb +4 -1
  25. data/lib/puppet/provider/package/windows.rb +5 -1
  26. data/lib/puppet/provider/service/upstart.rb +16 -6
  27. data/lib/puppet/settings.rb +10 -5
  28. data/lib/puppet/transaction.rb +8 -6
  29. data/lib/puppet/transaction/resource_harness.rb +1 -0
  30. data/lib/puppet/type/exec.rb +27 -5
  31. data/lib/puppet/type/file/mode.rb +6 -1
  32. data/lib/puppet/type/filebucket.rb +12 -8
  33. data/lib/puppet/util/command_line.rb +5 -1
  34. data/lib/puppet/util/log.rb +7 -2
  35. data/lib/puppet/util/pidlock.rb +14 -1
  36. data/lib/puppet/util/windows/process.rb +73 -5
  37. data/lib/puppet/util/windows/security.rb +29 -8
  38. data/lib/puppet/version.rb +1 -1
  39. data/locales/ja/puppet.po +149 -132
  40. data/locales/puppet.pot +197 -148
  41. data/man/man5/puppet.conf.5 +14 -6
  42. data/man/man8/puppet-agent.8 +1 -1
  43. data/man/man8/puppet-apply.8 +1 -1
  44. data/man/man8/puppet-catalog.8 +1 -1
  45. data/man/man8/puppet-config.8 +1 -1
  46. data/man/man8/puppet-describe.8 +1 -1
  47. data/man/man8/puppet-device.8 +1 -1
  48. data/man/man8/puppet-doc.8 +1 -1
  49. data/man/man8/puppet-epp.8 +1 -1
  50. data/man/man8/puppet-facts.8 +1 -1
  51. data/man/man8/puppet-filebucket.8 +6 -2
  52. data/man/man8/puppet-generate.8 +1 -1
  53. data/man/man8/puppet-help.8 +1 -1
  54. data/man/man8/puppet-key.8 +1 -1
  55. data/man/man8/puppet-lookup.8 +1 -1
  56. data/man/man8/puppet-man.8 +1 -1
  57. data/man/man8/puppet-module.8 +1 -1
  58. data/man/man8/puppet-node.8 +1 -1
  59. data/man/man8/puppet-parser.8 +1 -1
  60. data/man/man8/puppet-plugin.8 +1 -1
  61. data/man/man8/puppet-report.8 +1 -1
  62. data/man/man8/puppet-resource.8 +1 -1
  63. data/man/man8/puppet-script.8 +1 -1
  64. data/man/man8/puppet-ssl.8 +1 -1
  65. data/man/man8/puppet-status.8 +1 -1
  66. data/man/man8/puppet.8 +2 -2
  67. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load2.rb +11 -0
  68. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load3.rb +11 -0
  69. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load4.rb +11 -0
  70. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load5.rb +12 -0
  71. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/good_func_load.rb +9 -0
  72. data/spec/integration/provider/file/windows_spec.rb +162 -0
  73. data/spec/integration/type/file_spec.rb +0 -19
  74. data/spec/unit/application_spec.rb +8 -1
  75. data/spec/unit/configurer_spec.rb +6 -7
  76. data/spec/unit/confine/false_spec.rb +27 -0
  77. data/spec/unit/confine/true_spec.rb +27 -0
  78. data/spec/unit/defaults_spec.rb +0 -14
  79. data/spec/unit/network/http/connection_spec.rb +1 -1
  80. data/spec/unit/pops/loaders/loaders_spec.rb +70 -3
  81. data/spec/unit/pops/parser/locator_spec.rb +45 -0
  82. data/spec/unit/pops/parser/parse_heredoc_spec.rb +111 -15
  83. data/spec/unit/pops/types/type_mismatch_describer_spec.rb +9 -0
  84. data/spec/unit/provider/group/windows_adsi_spec.rb +7 -1
  85. data/spec/unit/provider/package/windows_spec.rb +12 -1
  86. data/spec/unit/provider/service/systemd_spec.rb +7 -5
  87. data/spec/unit/settings_spec.rb +36 -0
  88. data/spec/unit/transaction/resource_harness_spec.rb +26 -0
  89. data/spec/unit/transaction_spec.rb +29 -0
  90. data/spec/unit/type/exec_spec.rb +47 -0
  91. data/spec/unit/type/filebucket_spec.rb +8 -6
  92. data/spec/unit/util/command_line_spec.rb +23 -2
  93. data/spec/unit/util/execution_spec.rb +2 -2
  94. data/spec/unit/util/log_spec.rb +15 -0
  95. data/spec/unit/util/pidlock_spec.rb +21 -1
  96. data/spec/unit/util/storage_spec.rb +19 -19
  97. metadata +16 -3
  98. data/MAINTAINERS +0 -47
@@ -67,7 +67,10 @@ Puppet::Type.type(:group).provide :windows_adsi do
67
67
 
68
68
  def members
69
69
  @members ||= Puppet::Util::Windows::ADSI::Group.name_sid_hash(group.members)
70
- @members.keys
70
+
71
+ # @members.keys returns an array of SIDs. We need to convert those SIDs into
72
+ # names so that `puppet resource` prints the right output.
73
+ members_to_s(@members.keys).split(',')
71
74
  end
72
75
 
73
76
  def members=(members)
@@ -63,7 +63,11 @@ Puppet::Type.type(:package).provide(:windows, :parent => Puppet::Provider::Packa
63
63
  installer = Puppet::Provider::Package::Windows::Package.installer_class(resource)
64
64
 
65
65
  command = [installer.install_command(resource), install_options].flatten.compact.join(' ')
66
- output = execute(command, :failonfail => false, :combine => true, :cwd => File.dirname(resource[:source]), :suppress_window => true)
66
+ working_dir = File.dirname(resource[:source])
67
+ if !Puppet::FileSystem.exist?(working_dir) && resource[:source] =~ /\.msi"?\Z/i
68
+ working_dir = nil
69
+ end
70
+ output = execute(command, :failonfail => false, :combine => true, :cwd => working_dir, :suppress_window => true)
67
71
 
68
72
  check_result(output.exitstatus)
69
73
  end
@@ -28,12 +28,22 @@ Puppet::Type.type(:service).provide :upstart, :parent => :debian do
28
28
  # We only want to use upstart as our provider if the upstart daemon is running.
29
29
  # This can be checked by running `initctl version --quiet` on a machine that has
30
30
  # upstart installed.
31
- confine :true => begin
32
- initctl('version', '--quiet')
33
- true
34
- rescue
35
- false
36
- end
31
+ confine :true => lambda {
32
+ # Puppet::Util::Execution.execute does not currently work on jRuby.
33
+ # Unfortunately, since this confine is invoked whenever we check for
34
+ # provider suitability and since provider suitability is still checked
35
+ # on the master, this confine will still be invoked on the master. Thus
36
+ # to avoid raising an exception, we do an early return if we're running
37
+ # on jRuby.
38
+ next false if Puppet::Util::Platform.jruby?
39
+
40
+ begin
41
+ initctl('version', '--quiet')
42
+ true
43
+ rescue
44
+ false
45
+ end
46
+ }
37
47
 
38
48
  # upstart developer haven't implemented initctl enable/disable yet:
39
49
  # http://www.linuxplanet.com/linuxplanet/tutorials/7033/2/
@@ -255,7 +255,7 @@ class Puppet::Settings
255
255
  @global_defaults_initialized
256
256
  end
257
257
 
258
- def initialize_global_settings(args = [])
258
+ def initialize_global_settings(args = [], require_config = true)
259
259
  raise Puppet::DevError, _("Attempting to initialize global default settings more than once!") if global_defaults_initialized?
260
260
 
261
261
  # The first two phases of the lifecycle of a puppet application are:
@@ -264,7 +264,7 @@ class Puppet::Settings
264
264
  # 2) Parse the puppet config file(s).
265
265
 
266
266
  parse_global_options(args)
267
- parse_config_files
267
+ parse_config_files(require_config)
268
268
 
269
269
  @global_defaults_initialized = true
270
270
  end
@@ -590,14 +590,19 @@ class Puppet::Settings
590
590
  end
591
591
 
592
592
  # Parse the configuration file. Just provides thread safety.
593
- def parse_config_files
593
+ def parse_config_files(require_config = true)
594
594
  file = which_configuration_file
595
595
  if Puppet::FileSystem.exist?(file)
596
596
  begin
597
597
  text = read_file(file)
598
598
  rescue => detail
599
- Puppet.log_exception(detail, "Could not load #{file}: #{detail}")
600
- return
599
+ message = _("Could not load %{file}: %{detail}") % { file: file, detail: detail}
600
+ if require_config
601
+ Puppet.log_and_raise(detail, message)
602
+ else
603
+ Puppet.log_exception(detail, message)
604
+ return
605
+ end
601
606
  end
602
607
  else
603
608
  return
@@ -358,15 +358,17 @@ class Puppet::Transaction
358
358
  Puppet.debug "Prefetching #{provider_class.name} resources for #{type_name}"
359
359
  begin
360
360
  provider_class.prefetch(resources)
361
- rescue Exception => detail
362
- if !detail.is_a?(LoadError) && !detail.is_a?(Puppet::MissingCommand)
363
- raise unless Puppet.settings[:future_features]
364
-
365
- @prefetch_failed_providers[type_name][provider_class.name] = true
366
- end
361
+ rescue LoadError, Puppet::MissingCommand => detail
367
362
  #TRANSLATORS `prefetch` is a function name and should not be translated
368
363
  message = _("Could not prefetch %{type_name} provider '%{name}': %{detail}") % { type_name: type_name, name: provider_class.name, detail: detail }
369
364
  Puppet.log_exception(detail, message)
365
+ rescue StandardError => detail
366
+ message = _("Could not prefetch %{type_name} provider '%{name}': %{detail}") % { type_name: type_name, name: provider_class.name, detail: detail }
367
+ Puppet.log_exception(detail, message)
368
+
369
+ raise unless Puppet.settings[:future_features]
370
+
371
+ @prefetch_failed_providers[type_name][provider_class.name] = true
370
372
  end
371
373
  @prefetched_providers[type_name][provider_class.name] = true
372
374
  end
@@ -161,6 +161,7 @@ class Puppet::Transaction::ResourceHarness
161
161
  name = param.name.to_s
162
162
  event.message ||= _("could not create change error message for %{name}") % { name: name }
163
163
  event.calculate_corrective_change(@persistence.get_system_value(context.resource.ref, name))
164
+ event.message << ' (corrective)' if event.corrective_change
164
165
  context.record(event)
165
166
  event.send_log
166
167
  context.synced_params << param.name
@@ -581,7 +581,15 @@ module Puppet
581
581
  val = @parameters[check].value
582
582
  val = [val] unless val.is_a? Array
583
583
  val.each do |value|
584
- return false unless @parameters[check].check(value)
584
+ if !@parameters[check].check(value)
585
+ # Give a debug message so users can figure out what command would have been
586
+ # but don't print sensitive commands or parameters in the clear
587
+ cmdstring = @parameters[:command].sensitive ? "[command redacted]" : @parameters[:command].value
588
+
589
+ debug(_("'%{cmd}' won't be executed because of failed check '%{check}'") % { cmd: cmdstring, check: check })
590
+
591
+ return false
592
+ end
585
593
  end
586
594
  end
587
595
  }
@@ -614,11 +622,25 @@ module Puppet
614
622
 
615
623
  private
616
624
  def set_sensitive_parameters(sensitive_parameters)
617
- # Respect sensitive commands
618
- if sensitive_parameters.include?(:command)
619
- sensitive_parameters.delete(:command)
620
- parameter(:command).sensitive = true
625
+ # If any are sensitive, mark all as sensitive
626
+ sensitive = false
627
+ parameters_to_check = [:command, :unless, :onlyif]
628
+
629
+ parameters_to_check.each do |p|
630
+ if sensitive_parameters.include?(p)
631
+ sensitive_parameters.delete(p)
632
+ sensitive = true
633
+ end
621
634
  end
635
+
636
+ if sensitive
637
+ parameters_to_check.each do |p|
638
+ if parameters.include?(p)
639
+ parameter(p).sensitive = true
640
+ end
641
+ end
642
+ end
643
+
622
644
  super(sensitive_parameters)
623
645
  end
624
646
  end
@@ -116,8 +116,13 @@ module Puppet
116
116
  # If we're not following links and we're a link, then we just turn
117
117
  # off mode management entirely.
118
118
  def insync?(currentvalue)
119
+ if provider.respond_to?(:munge_windows_system_group)
120
+ munged_mode = provider.munge_windows_system_group(currentvalue, @should)
121
+ return false if munged_mode.nil?
122
+ currentvalue = munged_mode
123
+ end
119
124
  if stat = @resource.stat and stat.ftype == "link" and @resource[:links] != :follow
120
- self.debug "Not managing symlink mode"
125
+ self.debug _("Not managing symlink mode")
121
126
  return true
122
127
  else
123
128
  return super(currentvalue)
@@ -42,19 +42,23 @@ module Puppet
42
42
  end
43
43
 
44
44
  newparam(:server) do
45
- desc "The server providing the remote filebucket service. Defaults to the
46
- value of the `server` setting (that is, the currently configured
47
- puppet master server).
45
+ desc "The server providing the remote filebucket service.
48
46
 
49
- This setting is _only_ consulted if the `path` attribute is set to `false`."
50
- defaultto { Puppet[:server] }
47
+ This setting is _only_ consulted if the `path` attribute is set to `false`.
48
+
49
+ If this attribute is not specified, the first entry in the `server_list`
50
+ configuration setting is used, followed by the value of the `server` setting
51
+ if `server_list` is not set."
51
52
  end
52
53
 
53
54
  newparam(:port) do
54
- desc "The port on which the remote server is listening. Defaults to the
55
- value of the `masterport` setting, which is usually %s." % Puppet[:masterport]
55
+ desc "The port on which the remote server is listening.
56
+
57
+ This setting is _only_ consulted if the `path` attribute is set to `false`.
56
58
 
57
- defaultto { Puppet[:masterport] }
59
+ If this attribute is not specified, the first entry in the `server_list`
60
+ configuration setting is used, followed by the value of the `masterport`
61
+ setting if `server_list` is not set."
58
62
  end
59
63
 
60
64
  newparam(:path) do
@@ -64,8 +64,12 @@ module Puppet
64
64
  #
65
65
  # @return [void]
66
66
  def execute
67
+ require_config = true
68
+ if @argv.first =~ /help|-h|--help|-V|--version/
69
+ require_config = false
70
+ end
67
71
  Puppet::Util.exit_on_fail(_("Could not initialize global default settings")) do
68
- Puppet.initialize_settings(args)
72
+ Puppet.initialize_settings(args, require_config)
69
73
  end
70
74
 
71
75
  setpriority(Puppet[:priority])
@@ -60,7 +60,7 @@ class Puppet::Util::Log
60
60
  end
61
61
 
62
62
  def self.close_all
63
- destinations.keys.each { |dest|
63
+ @destinations.keys.each { |dest|
64
64
  close(dest)
65
65
  }
66
66
  #TRANSLATORS "Log.close_all" is a method name and should not be translated
@@ -147,7 +147,12 @@ class Puppet::Util::Log
147
147
  Puppet.log_exception(detail)
148
148
 
149
149
  # If this was our only destination, then add the console back in.
150
- newdestination(:console) if @destinations.empty? and (dest != :console and dest != "console")
150
+ if destinations.empty? && dest.intern != :console
151
+ newdestination(:console)
152
+ end
153
+
154
+ # Re-raise (end exit Puppet) because we could not set up logging correctly.
155
+ raise detail
151
156
  end
152
157
  end
153
158
 
@@ -54,7 +54,20 @@ class Puppet::Util::Pidlock
54
54
  begin
55
55
  Process.kill(0, lock_pid)
56
56
  rescue *errors
57
- @lockfile.unlock
57
+ return @lockfile.unlock
58
+ end
59
+
60
+ # Ensure the process associated with this pid is our process. If
61
+ # not, we can unlock the lockfile. For now this is only done on
62
+ # POSIX and Windows platforms (PUP-9247).
63
+ if Puppet.features.posix?
64
+ procname = Puppet::Util::Execution.execute(["ps", "-p", lock_pid, "-o", "comm="]).strip
65
+ @lockfile.unlock unless procname =~ /puppet(-.*)?$/
66
+ elsif Puppet.features.microsoft_windows?
67
+ # On Windows, we're checking if the filesystem path name of the running
68
+ # process is our vendored ruby:
69
+ exe_path = Puppet::Util::Windows::Process::get_process_image_name_by_pid(lock_pid)
70
+ @lockfile.unlock unless exe_path =~ /Puppet\\puppet\\bin\\ruby.exe/
58
71
  end
59
72
  end
60
73
  private :clear_if_stale
@@ -10,6 +10,10 @@ module Puppet::Util::Windows::Process
10
10
  WAIT_INTERVAL = 200
11
11
  # https://docs.microsoft.com/en-us/windows/desktop/ProcThread/process-creation-flags
12
12
  CREATE_NO_WINDOW = 0x08000000
13
+ # https://docs.microsoft.com/en-us/windows/desktop/ProcThread/process-security-and-access-rights
14
+ PROCESS_QUERY_INFORMATION = 0x0400
15
+ # https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
16
+ MAX_PATH_LENGTH = 32767
13
17
 
14
18
  def execute(command, arguments, stdin, stdout, stderr)
15
19
  create_args = {
@@ -24,12 +28,10 @@ module Puppet::Util::Windows::Process
24
28
  if arguments[:suppress_window]
25
29
  create_args[:creation_flags] = CREATE_NO_WINDOW
26
30
  end
27
- cwd = arguments[:cwd]
28
- if cwd
29
- Dir.chdir(cwd) { Process.create(create_args) }
30
- else
31
- Process.create(create_args)
31
+ if arguments[:cwd]
32
+ create_args[:cwd] = arguments[:cwd]
32
33
  end
34
+ Process.create(create_args)
33
35
  end
34
36
  module_function :execute
35
37
 
@@ -62,6 +64,26 @@ module Puppet::Util::Windows::Process
62
64
  end
63
65
  module_function :get_current_process
64
66
 
67
+ def open_process(desired_access, inherit_handle, process_id, &block)
68
+ phandle = nil
69
+ inherit = inherit_handle ? FFI::WIN32_TRUE : FFI::WIN32_FALSE
70
+ begin
71
+ phandle = OpenProcess(desired_access, inherit, process_id)
72
+ if phandle == FFI::Pointer::NULL_HANDLE
73
+ raise Puppet::Util::Windows::Error.new(
74
+ "OpenProcess(#{desired_access.to_s(8)}, #{inherit}, #{process_id})")
75
+ end
76
+
77
+ yield phandle
78
+ ensure
79
+ FFI::WIN32.CloseHandle(phandle) if phandle
80
+ end
81
+
82
+ # phandle has had CloseHandle called against it, so nothing to return
83
+ nil
84
+ end
85
+ module_function :open_process
86
+
65
87
  def open_process_token(handle, desired_access, &block)
66
88
  token_handle = nil
67
89
  begin
@@ -97,6 +119,32 @@ module Puppet::Util::Windows::Process
97
119
  end
98
120
  module_function :with_process_token
99
121
 
122
+ def get_process_image_name_by_pid(pid)
123
+ image_name = ""
124
+
125
+ open_process(PROCESS_QUERY_INFORMATION, false, pid) do |phandle|
126
+
127
+ FFI::MemoryPointer.new(:dword, 1) do |exe_name_length_ptr|
128
+ # Add 1 for the null terminator, and UTF is 2 bytes/char:
129
+ max_path_length = (MAX_PATH_LENGTH + 1) * 2
130
+ exe_name_length_ptr.write_dword(max_path_length)
131
+ FFI::MemoryPointer.new(max_path_length) do |exe_name_ptr|
132
+ use_win32_path_format = 0
133
+ result = QueryFullProcessImageNameW(phandle, use_win32_path_format, exe_name_ptr, exe_name_length_ptr)
134
+ if result == FFI::WIN32_FALSE
135
+ raise Puppet::Util::Windows::Error.new(
136
+ "QueryFullProcessImageNameW(phandle, #{use_win32_path_format}, " +
137
+ "exe_name_ptr, #{max_path_length}")
138
+ end
139
+ image_name = exe_name_ptr.read_wide_string(MAX_PATH_LENGTH + 1)
140
+ end
141
+ end
142
+ end
143
+
144
+ image_name
145
+ end
146
+ module_function :get_process_image_name_by_pid
147
+
100
148
  def lookup_privilege_value(name, system_name = '', &block)
101
149
  FFI::MemoryPointer.new(LUID.size) do |luid_ptr|
102
150
  result = LookupPrivilegeValueW(
@@ -366,6 +414,16 @@ module Puppet::Util::Windows::Process
366
414
  attach_function_private :SetEnvironmentVariableW,
367
415
  [:lpcwstr, :lpcwstr], :win32_bool
368
416
 
417
+ # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx
418
+ # HANDLE WINAPI OpenProcess(
419
+ # _In_ DWORD DesiredAccess,
420
+ # _In_ BOOL InheritHandle,
421
+ # _In_ DWORD ProcessId
422
+ # );
423
+ ffi_lib :kernel32
424
+ attach_function_private :OpenProcess,
425
+ [:dword, :win32_bool, :dword], :handle
426
+
369
427
  # https://msdn.microsoft.com/en-us/library/windows/desktop/aa379295(v=vs.85).aspx
370
428
  # BOOL WINAPI OpenProcessToken(
371
429
  # _In_ HANDLE ProcessHandle,
@@ -376,6 +434,16 @@ module Puppet::Util::Windows::Process
376
434
  attach_function_private :OpenProcessToken,
377
435
  [:handle, :dword, :phandle], :win32_bool
378
436
 
437
+ # https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-queryfullprocessimagenamew
438
+ # BOOL WINAPI QueryFullProcessImageName(
439
+ # _In_ HANDLE hProcess,
440
+ # _In_ DWORD dwFlags,
441
+ # _Out_ LPWSTR lpExeName,
442
+ # _In_ PDWORD lpdwSize,
443
+ # );
444
+ ffi_lib :kernel32
445
+ attach_function_private :QueryFullProcessImageNameW,
446
+ [:handle, :dword, :lpwstr, :pdword], :win32_bool
379
447
 
380
448
  # https://msdn.microsoft.com/en-us/library/windows/desktop/aa379261(v=vs.85).aspx
381
449
  # typedef struct _LUID {
@@ -274,7 +274,7 @@ module Puppet::Util::Windows::Security
274
274
  # mode. Only a user with the SE_BACKUP_NAME and SE_RESTORE_NAME
275
275
  # privileges in their process token can change the mode for objects
276
276
  # that they do not have read and write access to.
277
- def set_mode(mode, path, protected = true)
277
+ def set_mode(mode, path, protected = true, managing_owner = false, managing_group = false)
278
278
  sd = get_security_descriptor(path)
279
279
  well_known_world_sid = Puppet::Util::Windows::SID::Everyone
280
280
  well_known_nobody_sid = Puppet::Util::Windows::SID::Nobody
@@ -319,6 +319,8 @@ module Puppet::Util::Windows::Security
319
319
  nobody_allow |= FILE::FILE_APPEND_DATA;
320
320
  end
321
321
 
322
+ isownergroup = sd.owner == sd.group
323
+
322
324
  # caller is NOT managing SYSTEM by using group or owner, so set to FULL
323
325
  if ! [sd.owner, sd.group].include? well_known_system_sid
324
326
  # we don't check S_ISYSTEM_MISSING bit, but automatically carry over existing SYSTEM perms
@@ -328,15 +330,35 @@ module Puppet::Util::Windows::Security
328
330
  # It is possible to set SYSTEM with a mode other than Full Control (7) however this makes no sense and in practical terms
329
331
  # should not be done. We can trap these instances and correct them before being applied.
330
332
  if (sd.owner == well_known_system_sid) && (owner_allow != FILE::FILE_ALL_ACCESS)
331
- #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated
332
- Puppet.debug _("An attempt to set mode %{mode} on item %{path} would result in the owner, SYSTEM, to have less than Full Control rights. This attempt has been corrected to Full Control") % { mode: mode.to_s(8), path: path }
333
- owner_allow = FILE::FILE_ALL_ACCESS
333
+ # If owner and group are both SYSTEM but group is unmanaged the control rights of system will be set to FullControl by
334
+ # the unmanaged group, so there is no need for the warning
335
+ if managing_owner && (!isownergroup || managing_group)
336
+ #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated
337
+ Puppet.warning _("Setting control rights for %{path} owner SYSTEM to less than Full Control rights. Setting SYSTEM rights to less than Full Control may have unintented consequences for operations on this file") % { path: path }
338
+ elsif managing_owner && isownergroup
339
+ #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated
340
+ Puppet.debug _("%{path} owner and group both set to user SYSTEM, but group is not managed directly: SYSTEM user rights will be set to FullControl by group") % { path: path }
341
+ else
342
+ #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated
343
+ Puppet.debug _("An attempt to set mode %{mode} on item %{path} would result in the owner, SYSTEM, to have less than Full Control rights. This attempt has been corrected to Full Control") % { mode: mode.to_s(8), path: path }
344
+ owner_allow = FILE::FILE_ALL_ACCESS
345
+ end
334
346
  end
335
347
 
336
348
  if (sd.group == well_known_system_sid) && (group_allow != FILE::FILE_ALL_ACCESS)
337
- #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated
338
- Puppet.debug _("An attempt to set mode %{mode} on item %{path} would result in the group, SYSTEM, to have less than Full Control rights. This attempt has been corrected to Full Control") % { mode: mode.to_s(8), path: path }
339
- group_allow = FILE::FILE_ALL_ACCESS
349
+ # If owner and group are both SYSTEM but owner is unmanaged the control rights of system will be set to FullControl by
350
+ # the unmanaged owner, so there is no need for the warning.
351
+ if managing_group && (!isownergroup || managing_owner)
352
+ #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated
353
+ Puppet.warning _("Setting control rights for %{path} group SYSTEM to less than Full Control rights. Setting SYSTEM rights to less than Full Control may have unintented consequences for operations on this file") % { path: path }
354
+ elsif managing_group && isownergroup
355
+ #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated
356
+ Puppet.debug _("%{path} owner and group both set to user SYSTEM, but owner is not managed directly: SYSTEM user rights will be set to FullControl by owner") % { path: path }
357
+ else
358
+ #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated
359
+ Puppet.debug _("An attempt to set mode %{mode} on item %{path} would result in the group, SYSTEM, to have less than Full Control rights. This attempt has been corrected to Full Control") % { mode: mode.to_s(8), path: path }
360
+ group_allow = FILE::FILE_ALL_ACCESS
361
+ end
340
362
  end
341
363
  end
342
364
 
@@ -353,7 +375,6 @@ module Puppet::Util::Windows::Security
353
375
  end
354
376
 
355
377
  # if owner and group the same, then map group permissions to the one owner ACE
356
- isownergroup = sd.owner == sd.group
357
378
  if isownergroup
358
379
  owner_allow |= group_allow
359
380
  end