puppet 6.0.0 → 6.1.0

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.
Files changed (259) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/Gemfile.lock +20 -20
  4. data/Guardfile.example +76 -0
  5. data/LICENSE +189 -4
  6. data/README.md +3 -3
  7. data/Rakefile +5 -2
  8. data/ext/solaris/smf/svc-puppetd +8 -1
  9. data/ext/solaris/smf/svc-puppetmasterd +8 -1
  10. data/lib/puppet/application/apply.rb +100 -59
  11. data/lib/puppet/application/cert.rb +4 -114
  12. data/lib/puppet/application/device.rb +48 -32
  13. data/lib/puppet/application/script.rb +1 -1
  14. data/lib/puppet/application/ssl.rb +135 -51
  15. data/lib/puppet/application.rb +5 -0
  16. data/lib/puppet/configurer.rb +2 -3
  17. data/lib/puppet/defaults.rb +33 -49
  18. data/lib/puppet/etc.rb +20 -0
  19. data/lib/puppet/face/config.rb +3 -3
  20. data/lib/puppet/face/key.rb +1 -1
  21. data/lib/puppet/face/node/clean.rb +0 -1
  22. data/lib/puppet/feature/base.rb +1 -1
  23. data/lib/puppet/file_bucket/dipper.rb +1 -1
  24. data/lib/puppet/file_serving/fileset.rb +1 -1
  25. data/lib/puppet/functions/abs.rb +1 -1
  26. data/lib/puppet/functions/new.rb +1 -1
  27. data/lib/puppet/module/task.rb +29 -38
  28. data/lib/puppet/pal/catalog_compiler.rb +96 -0
  29. data/lib/puppet/pal/compiler.rb +221 -0
  30. data/lib/puppet/pal/function_signature.rb +52 -0
  31. data/lib/puppet/pal/json_catalog_encoder.rb +67 -0
  32. data/lib/puppet/pal/pal_api.rb +15 -0
  33. data/lib/puppet/pal/pal_impl.rb +523 -0
  34. data/lib/puppet/pal/plan_signature.rb +71 -0
  35. data/lib/puppet/pal/script_compiler.rb +71 -0
  36. data/lib/puppet/pal/task_signature.rb +58 -0
  37. data/lib/puppet/parser/catalog_compiler.rb +24 -0
  38. data/lib/puppet/parser/compiler.rb +3 -1
  39. data/lib/puppet/parser/functions/generate.rb +7 -6
  40. data/lib/puppet/plugins/configuration.rb +5 -1
  41. data/lib/puppet/pops/evaluator/collectors/abstract_collector.rb +3 -1
  42. data/lib/puppet/pops/evaluator/deferred_resolver.rb +3 -0
  43. data/lib/puppet/pops/evaluator/evaluator_impl.rb +5 -1
  44. data/lib/puppet/pops/evaluator/external_syntax_support.rb +3 -3
  45. data/lib/puppet/pops/evaluator/runtime3_converter.rb +2 -2
  46. data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +19 -10
  47. data/lib/puppet/pops/loader/task_instantiator.rb +13 -70
  48. data/lib/puppet/pops/parser/heredoc_support.rb +1 -2
  49. data/lib/puppet/pops/parser/lexer2.rb +1 -1
  50. data/lib/puppet/pops/pcore.rb +10 -33
  51. data/lib/puppet/pops/serialization/to_data_converter.rb +9 -1
  52. data/lib/puppet/pops/serialization.rb +1 -0
  53. data/lib/puppet/pops/types/p_timespan_type.rb +2 -2
  54. data/lib/puppet/pops/types/string_converter.rb +18 -4
  55. data/lib/puppet/pops/validation/checker4_0.rb +17 -2
  56. data/lib/puppet/provider/exec.rb +59 -57
  57. data/lib/puppet/provider/group/aix.rb +18 -2
  58. data/lib/puppet/provider/group/windows_adsi.rb +7 -3
  59. data/lib/puppet/provider/nameservice.rb +1 -25
  60. data/lib/puppet/provider/package/dnf.rb +2 -0
  61. data/lib/puppet/provider/package/pkgng.rb +37 -21
  62. data/lib/puppet/provider/package/portage.rb +2 -2
  63. data/lib/puppet/provider/package/windows/exe_package.rb +16 -10
  64. data/lib/puppet/provider/package/windows/msi_package.rb +8 -0
  65. data/lib/puppet/provider/package/windows/package.rb +9 -1
  66. data/lib/puppet/provider/package/windows.rb +2 -2
  67. data/lib/puppet/provider/package/yum.rb +1 -1
  68. data/lib/puppet/provider/parsedfile.rb +25 -4
  69. data/lib/puppet/provider/service/launchd.rb +19 -3
  70. data/lib/puppet/provider/service/smf.rb +54 -0
  71. data/lib/puppet/provider/service/systemd.rb +19 -0
  72. data/lib/puppet/provider/service/upstart.rb +1 -0
  73. data/lib/puppet/provider/service/windows.rb +22 -5
  74. data/lib/puppet/provider/user/aix.rb +48 -2
  75. data/lib/puppet/provider/user/useradd.rb +2 -10
  76. data/lib/puppet/provider/user/windows_adsi.rb +9 -1
  77. data/lib/puppet/resource/catalog.rb +1 -5
  78. data/lib/puppet/resource.rb +3 -1
  79. data/lib/puppet/ssl/host.rb +26 -16
  80. data/lib/puppet/syntax_checkers/epp.rb +34 -0
  81. data/lib/puppet/syntax_checkers/pp.rb +34 -0
  82. data/lib/puppet/transaction/event_manager.rb +13 -1
  83. data/lib/puppet/transaction/persistence.rb +1 -1
  84. data/lib/puppet/transaction/resource_harness.rb +3 -1
  85. data/lib/puppet/type/group.rb +29 -1
  86. data/lib/puppet/type/package.rb +5 -1
  87. data/lib/puppet/type/resources.rb +12 -2
  88. data/lib/puppet/type/schedule.rb +7 -0
  89. data/lib/puppet/type/service.rb +12 -0
  90. data/lib/puppet/type/user.rb +5 -2
  91. data/lib/puppet/type.rb +6 -0
  92. data/lib/puppet/util/command_line.rb +2 -3
  93. data/lib/puppet/util/execution.rb +15 -1
  94. data/lib/puppet/util/filetype.rb +56 -8
  95. data/lib/puppet/util/log/destinations.rb +3 -2
  96. data/lib/puppet/util/logging.rb +3 -2
  97. data/lib/puppet/util/posix.rb +15 -0
  98. data/lib/puppet/util/selinux.rb +1 -1
  99. data/lib/puppet/util/storage.rb +12 -0
  100. data/lib/puppet/util/windows/adsi.rb +79 -2
  101. data/lib/puppet/util/windows/api_types.rb +1 -1
  102. data/lib/puppet/util/windows/process.rb +23 -3
  103. data/lib/puppet/util/windows/registry.rb +29 -5
  104. data/lib/puppet/util/windows/security.rb +14 -0
  105. data/lib/puppet/util/windows/service.rb +294 -74
  106. data/lib/puppet/util/windows/user.rb +3 -5
  107. data/lib/puppet/util.rb +7 -3
  108. data/lib/puppet/version.rb +1 -1
  109. data/lib/puppet.rb +1 -0
  110. data/lib/puppet_pal.rb +5 -1099
  111. data/locales/ja/puppet.po +952 -986
  112. data/locales/puppet.pot +592 -347
  113. data/man/man5/puppet.conf.5 +26 -31
  114. data/man/man8/puppet-agent.8 +1 -1
  115. data/man/man8/puppet-apply.8 +1 -1
  116. data/man/man8/puppet-catalog.8 +1 -1
  117. data/man/man8/puppet-config.8 +4 -4
  118. data/man/man8/puppet-describe.8 +1 -1
  119. data/man/man8/puppet-device.8 +23 -19
  120. data/man/man8/puppet-doc.8 +1 -1
  121. data/man/man8/puppet-epp.8 +1 -1
  122. data/man/man8/puppet-facts.8 +1 -1
  123. data/man/man8/puppet-filebucket.8 +1 -1
  124. data/man/man8/puppet-generate.8 +1 -1
  125. data/man/man8/puppet-help.8 +1 -1
  126. data/man/man8/puppet-key.8 +2 -2
  127. data/man/man8/puppet-lookup.8 +1 -1
  128. data/man/man8/puppet-man.8 +1 -1
  129. data/man/man8/puppet-module.8 +1 -1
  130. data/man/man8/puppet-node.8 +1 -1
  131. data/man/man8/puppet-parser.8 +1 -1
  132. data/man/man8/puppet-plugin.8 +1 -1
  133. data/man/man8/puppet-report.8 +1 -1
  134. data/man/man8/puppet-resource.8 +1 -1
  135. data/man/man8/puppet-script.8 +1 -1
  136. data/man/man8/puppet-ssl.8 +26 -3
  137. data/man/man8/puppet-status.8 +1 -1
  138. data/man/man8/puppet.8 +2 -2
  139. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load.rb +11 -0
  140. data/spec/fixtures/unit/provider/package/pkgng/pkg.query +7 -1
  141. data/spec/fixtures/unit/provider/package/pkgng/pkg.query.zsh +1 -0
  142. data/spec/fixtures/unit/provider/service/smf/svcs_fmri.out +6 -0
  143. data/spec/fixtures/unit/provider/service/smf/svcs_multiple_fmris.out +13 -0
  144. data/spec/integration/application/apply_spec.rb +4 -1
  145. data/spec/integration/parser/collection_spec.rb +4 -8
  146. data/spec/integration/provider/service/windows_spec.rb +5 -5
  147. data/spec/integration/ssl/key_spec.rb +0 -4
  148. data/spec/integration/transaction_spec.rb +559 -0
  149. data/spec/integration/type/file_spec.rb +6 -6
  150. data/spec/integration/util/windows/registry_spec.rb +39 -0
  151. data/spec/integration/util/windows/security_spec.rb +10 -7
  152. data/spec/integration/util/windows/user_spec.rb +37 -17
  153. data/spec/lib/puppet/test_ca.rb +1 -1
  154. data/spec/spec_helper.rb +1 -1
  155. data/spec/unit/agent_spec.rb +2 -2
  156. data/spec/unit/application/apply_spec.rb +55 -2
  157. data/spec/unit/application/device_spec.rb +10 -7
  158. data/spec/unit/application/face_base_spec.rb +1 -1
  159. data/spec/unit/application/lookup_spec.rb +2 -1
  160. data/spec/unit/application/ssl_spec.rb +178 -109
  161. data/spec/unit/application_spec.rb +29 -11
  162. data/spec/unit/configurer/downloader_spec.rb +1 -1
  163. data/spec/unit/configurer_spec.rb +16 -5
  164. data/spec/unit/etc_spec.rb +25 -0
  165. data/spec/unit/face/node_spec.rb +1 -3
  166. data/spec/unit/face/parser_spec.rb +15 -0
  167. data/spec/unit/file_serving/fileset_spec.rb +11 -11
  168. data/spec/unit/functions/logging_spec.rb +10 -3
  169. data/spec/unit/indirector/catalog/json_spec.rb +9 -3
  170. data/spec/unit/indirector/yaml_spec.rb +1 -1
  171. data/spec/unit/network/http/connection_spec.rb +2 -2
  172. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +36 -0
  173. data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +22 -4
  174. data/spec/unit/pops/loaders/loader_spec.rb +9 -17
  175. data/spec/unit/pops/loaders/loaders_spec.rb +48 -0
  176. data/spec/unit/pops/loaders/module_loaders_spec.rb +7 -7
  177. data/spec/unit/pops/parser/parse_heredoc_spec.rb +16 -0
  178. data/spec/unit/pops/serialization/to_from_hr_spec.rb +9 -0
  179. data/spec/unit/pops/types/p_timespan_type_spec.rb +22 -0
  180. data/spec/unit/pops/types/p_timestamp_type_spec.rb +19 -0
  181. data/spec/unit/pops/types/string_converter_spec.rb +25 -1
  182. data/spec/unit/pops/types/task_spec.rb +42 -116
  183. data/spec/unit/pops/validator/validator_spec.rb +24 -10
  184. data/spec/unit/provider/exec/posix_spec.rb +24 -0
  185. data/spec/unit/provider/group/aix_spec.rb +20 -6
  186. data/spec/unit/provider/group/ldap_spec.rb +22 -25
  187. data/spec/unit/provider/group/pw_spec.rb +7 -10
  188. data/spec/unit/provider/group/windows_adsi_spec.rb +42 -33
  189. data/spec/unit/provider/nameservice/directoryservice_spec.rb +97 -103
  190. data/spec/unit/provider/package/aix_spec.rb +5 -8
  191. data/spec/unit/provider/package/apt_spec.rb +3 -6
  192. data/spec/unit/provider/package/dnf_spec.rb +38 -25
  193. data/spec/unit/provider/package/dpkg_spec.rb +18 -21
  194. data/spec/unit/provider/package/freebsd_spec.rb +4 -7
  195. data/spec/unit/provider/package/gem_spec.rb +41 -41
  196. data/spec/unit/provider/package/hpux_spec.rb +7 -10
  197. data/spec/unit/provider/package/macports_spec.rb +13 -15
  198. data/spec/unit/provider/package/nim_spec.rb +3 -10
  199. data/spec/unit/provider/package/openbsd_spec.rb +14 -17
  200. data/spec/unit/provider/package/pip3_spec.rb +3 -6
  201. data/spec/unit/provider/package/pip_spec.rb +45 -49
  202. data/spec/unit/provider/package/pkgin_spec.rb +13 -18
  203. data/spec/unit/provider/package/pkgng_spec.rb +32 -27
  204. data/spec/unit/provider/package/puppet_gem_spec.rb +6 -9
  205. data/spec/unit/provider/package/tdnf_spec.rb +9 -12
  206. data/spec/unit/provider/package/windows/exe_package_spec.rb +3 -3
  207. data/spec/unit/provider/package/windows_spec.rb +4 -4
  208. data/spec/unit/provider/package/yum_spec.rb +30 -16
  209. data/spec/unit/provider/package/zypper_spec.rb +17 -19
  210. data/spec/unit/provider/service/bsd_spec.rb +7 -9
  211. data/spec/unit/provider/service/daemontools_spec.rb +12 -16
  212. data/spec/unit/provider/service/debian_spec.rb +6 -10
  213. data/spec/unit/provider/service/freebsd_spec.rb +2 -2
  214. data/spec/unit/provider/service/launchd_spec.rb +19 -0
  215. data/spec/unit/provider/service/openbsd_spec.rb +13 -17
  216. data/spec/unit/provider/service/rcng_spec.rb +2 -4
  217. data/spec/unit/provider/service/redhat_spec.rb +12 -11
  218. data/spec/unit/provider/service/runit_spec.rb +7 -14
  219. data/spec/unit/provider/service/smf_spec.rb +77 -13
  220. data/spec/unit/provider/service/src_spec.rb +11 -16
  221. data/spec/unit/provider/service/systemd_spec.rb +39 -1
  222. data/spec/unit/provider/service/windows_spec.rb +39 -7
  223. data/spec/unit/provider/user/aix_spec.rb +43 -2
  224. data/spec/unit/provider/user/hpux_spec.rb +3 -5
  225. data/spec/unit/provider/user/ldap_spec.rb +29 -32
  226. data/spec/unit/provider/user/pw_spec.rb +10 -13
  227. data/spec/unit/provider/user/useradd_spec.rb +2 -2
  228. data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
  229. data/spec/unit/puppet_pal_2pec.rb +6 -6
  230. data/spec/unit/puppet_pal_catalog_spec.rb +58 -0
  231. data/spec/unit/resource/catalog_spec.rb +2 -2
  232. data/spec/unit/resource_spec.rb +31 -0
  233. data/spec/unit/ssl/host_spec.rb +22 -1
  234. data/spec/unit/ssl/key_spec.rb +2 -4
  235. data/spec/unit/task_spec.rb +50 -5
  236. data/spec/unit/transaction/event_manager_spec.rb +12 -1
  237. data/spec/unit/transaction/persistence_spec.rb +4 -4
  238. data/spec/unit/transaction/resource_harness_spec.rb +18 -0
  239. data/spec/unit/type/group_spec.rb +11 -3
  240. data/spec/unit/type/resources_spec.rb +18 -0
  241. data/spec/unit/type/service_spec.rb +27 -1
  242. data/spec/unit/util/execution_spec.rb +77 -0
  243. data/spec/unit/util/filetype_spec.rb +13 -5
  244. data/spec/unit/util/log/destinations_spec.rb +10 -0
  245. data/spec/unit/util/logging_spec.rb +58 -41
  246. data/spec/unit/util/monkey_patches_spec.rb +18 -5
  247. data/spec/unit/util/posix_spec.rb +28 -0
  248. data/spec/unit/util/selinux_spec.rb +4 -0
  249. data/spec/unit/util/storage_spec.rb +107 -0
  250. data/spec/unit/util/suidmanager_spec.rb +1 -3
  251. data/spec/unit/util/windows/adsi_spec.rb +95 -0
  252. data/spec/unit/util/windows/service_spec.rb +377 -131
  253. metadata +24 -11
  254. data/ext/autotest/Rakefile +0 -8
  255. data/ext/autotest/config +0 -43
  256. data/ext/autotest/readme.rst +0 -16
  257. data/spec/fixtures/unit/provider/package/pkgng/pkg.info +0 -7
  258. data/spec/fixtures/unit/provider/package/pkgng/pkg.query_absent +0 -1
  259. data/spec/watchr.rb +0 -137
@@ -409,7 +409,10 @@ module Puppet
409
409
  resource at the same time. For instance, Puppet creates a home directory for a managed
410
410
  user if `ensure => present` and the user does not exist at the time of the Puppet run.
411
411
  If the home directory is then deleted manually, Puppet will not recreate it on the next
412
- run."
412
+ run.
413
+
414
+ Note that on Windows, this manages creation/deletion of the user profile instead of the
415
+ home directory. The user profile is stored in the `C:\Users\<username>` directory."
413
416
 
414
417
  defaultto false
415
418
 
@@ -555,7 +558,7 @@ module Puppet
555
558
  newparam(:auth_membership) do
556
559
  desc "Whether specified auths should be considered the **complete list**
557
560
  (`inclusive`) or the **minimum list** (`minimum`) of auths the user
558
- has."
561
+ has. This setting is specific to managing Solaris authorizations."
559
562
 
560
563
  newvalues(:inclusive, :minimum)
561
564
 
data/lib/puppet/type.rb CHANGED
@@ -391,6 +391,12 @@ class Type
391
391
  @key_attributes_cache ||= key_attribute_parameters.collect { |p| p.name }
392
392
  end
393
393
 
394
+ # Returns any parameters that should be included by default in puppet resource's output
395
+ # @return [Array<Symbol>] the parameters to include
396
+ def self.parameters_to_include
397
+ []
398
+ end
399
+
394
400
  # Returns a mapping from the title string to setting of attribute values.
395
401
  # This default implementation provides a mapping of title to the one and only _namevar_ present
396
402
  # in the type's definition.
@@ -106,7 +106,7 @@ module Puppet
106
106
  def run
107
107
  # For most applications, we want to be able to load code from the modulepath,
108
108
  # such as apply, describe, resource, and faces.
109
- # For agent, we only want to load pluginsync'ed code from libdir.
109
+ # For agent and device in agent mode, we only want to load pluginsync'ed code from libdir.
110
110
  # For master, we shouldn't ever be loading per-environment code into the master's
111
111
  # ruby process, but that requires fixing (#17210, #12173, #8750). So for now
112
112
  # we try to restrict to only code that can be autoloaded from the node's
@@ -116,8 +116,7 @@ module Puppet
116
116
  # have an appropriate application-wide current_environment set.
117
117
  # If we cannot find the configured environment, which may not exist,
118
118
  # we do not attempt to add plugin directories to the load path.
119
- #
120
- if @subcommand_name != 'master' and @subcommand_name != 'agent'
119
+ unless @subcommand_name == 'master' || @subcommand_name == 'agent' || (@subcommand_name == 'device' && (['--apply', '--facts', '--resource'] - @command_line.args).empty?)
121
120
  if configured_environment = Puppet.lookup(:environments).get(Puppet[:environment])
122
121
  configured_environment.each_plugin_directory do |dir|
123
122
  $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
@@ -114,6 +114,9 @@ module Puppet::Util::Execution
114
114
  # an Array the first element should be the executable and the rest of the
115
115
  # elements should be the individual arguments to that executable.
116
116
  # @param options [Hash] a Hash of options
117
+ # @option options [String] :cwd the directory from which to run the command. Raises an error if the directory does not exist.
118
+ # This option is only available on the agent. It cannot be used on the master, meaning it cannot be used in, for example,
119
+ # regular functions, hiera backends, or report processors.
117
120
  # @option options [Boolean] :failonfail if this value is set to true, then this method will raise an error if the
118
121
  # command is not executed successfully.
119
122
  # @option options [Integer, String] :uid (nil) the user id of the user that the process should be run as. Will be ignored if the
@@ -154,6 +157,7 @@ module Puppet::Util::Execution
154
157
  :override_locale => true,
155
158
  :custom_environment => {},
156
159
  :sensitive => false,
160
+ :suppress_window => false,
157
161
  }
158
162
 
159
163
  options = default_options.merge(options)
@@ -186,6 +190,11 @@ module Puppet::Util::Execution
186
190
 
187
191
  null_file = Puppet::Util::Platform.windows? ? 'NUL' : '/dev/null'
188
192
 
193
+ cwd = options[:cwd]
194
+ if cwd && ! Puppet::FileSystem.directory?(cwd)
195
+ raise ArgumentError, _("Working directory %{cwd} does not exist!") % { cwd: cwd }
196
+ end
197
+
189
198
  begin
190
199
  stdin = Puppet::FileSystem.open(options[:stdinfile] || null_file, nil, 'r')
191
200
  # On Windows, continue to use the file-based approach to avoid breaking people's existing
@@ -320,7 +329,6 @@ module Puppet::Util::Execution
320
329
  #
321
330
  def self.execute_posix(command, options, stdin, stdout, stderr)
322
331
  child_pid = Puppet::Util.safe_posix_fork(stdin, stdout, stderr) do
323
-
324
332
  # We can't just call Array(command), and rely on it returning
325
333
  # things like ['foo'], when passed ['foo'], because
326
334
  # Array(command) will call command.to_a internally, which when
@@ -329,6 +337,12 @@ module Puppet::Util::Execution
329
337
  command = [command].flatten
330
338
  Process.setsid
331
339
  begin
340
+ # We need to chdir to our cwd before changing privileges as there's a
341
+ # chance that the user may not have permissions to access the cwd, which
342
+ # would cause execute_posix to fail.
343
+ cwd = options[:cwd]
344
+ Dir.chdir(cwd) if cwd
345
+
332
346
  Puppet::Util::SUIDManager.change_privileges(options[:uid], options[:gid], true)
333
347
 
334
348
  # if the caller has requested that we override locale environment variables,
@@ -166,6 +166,12 @@ class Puppet::Util::FileType
166
166
  end
167
167
 
168
168
  # Handle Linux-style cron tabs.
169
+ #
170
+ # TODO: We can possibly eliminate the "-u <username>" option in cmdbase
171
+ # by just running crontab under <username>'s uid (like we do for suntab
172
+ # and aixtab). It may be worth investigating this alternative
173
+ # implementation in the future. This way, we can refactor all three of
174
+ # our cron file types into a common crontab file type.
169
175
  newfiletype(:crontab) do
170
176
  def initialize(user)
171
177
  self.path = user
@@ -185,21 +191,47 @@ class Puppet::Util::FileType
185
191
 
186
192
  # Read a specific @path's cron tab.
187
193
  def read
188
- %x{#{cmdbase} -l 2>/dev/null}
194
+ unless Puppet::Util.uid(@path)
195
+ Puppet.debug _("The %{path} user does not exist. Treating their crontab file as empty in case Puppet creates them in the middle of the run.") % { path: @path }
196
+
197
+ return ""
198
+ end
199
+
200
+ Puppet::Util::Execution.execute("#{cmdbase} -l", failonfail: true, combine: true)
201
+ rescue => detail
202
+ case detail.to_s
203
+ when /no crontab for/
204
+ return ""
205
+ when /are not allowed to/
206
+ Puppet.debug _("The %{path} user is not authorized to use cron. Their crontab file is treated as empty in case Puppet authorizes them in the middle of the run (by, for example, modifying the cron.deny or cron.allow files).") % { path: @path }
207
+
208
+ return ""
209
+ else
210
+ raise FileReadError, _("Could not read crontab for %{path}: %{detail}") % { path: @path, detail: detail }, detail.backtrace
211
+ end
189
212
  end
190
213
 
191
214
  # Remove a specific @path's cron tab.
192
215
  def remove
216
+ cmd = "#{cmdbase} -r"
193
217
  if %w{Darwin FreeBSD DragonFly}.include?(Facter.value("operatingsystem"))
194
- %x{/bin/echo yes | #{cmdbase} -r 2>/dev/null}
195
- else
196
- %x{#{cmdbase} -r 2>/dev/null}
218
+ cmd = "/bin/echo yes | #{cmd}"
197
219
  end
220
+
221
+ Puppet::Util::Execution.execute(cmd, failonfail: true, combine: true)
198
222
  end
199
223
 
200
224
  # Overwrite a specific @path's cron tab; must be passed the @path name
201
225
  # and the text with which to create the cron tab.
226
+ #
227
+ # TODO: We should refactor this at some point to make it identical to the
228
+ # :aixtab and :suntab's write methods so that, at the very least, the pipe
229
+ # is not created and the crontab command's errors are not swallowed.
202
230
  def write(text)
231
+ unless Puppet::Util.uid(@path)
232
+ raise Puppet::Error, _("Cannot write the %{path} user's crontab: The user does not exist") % { path: @path }
233
+ end
234
+
203
235
  # this file is managed by the OS and should be using system encoding
204
236
  IO.popen("#{cmdbase()} -", "w", :encoding => Encoding.default_external) { |p|
205
237
  p.print text
@@ -224,13 +256,21 @@ class Puppet::Util::FileType
224
256
  newfiletype(:suntab) do
225
257
  # Read a specific @path's cron tab.
226
258
  def read
259
+ unless Puppet::Util.uid(@path)
260
+ Puppet.debug _("The %{path} user does not exist. Treating their crontab file as empty in case Puppet creates them in the middle of the run.") % { path: @path }
261
+
262
+ return ""
263
+ end
264
+
227
265
  Puppet::Util::Execution.execute(%w{crontab -l}, cronargs)
228
266
  rescue => detail
229
267
  case detail.to_s
230
268
  when /can't open your crontab/
231
269
  return ""
232
270
  when /you are not authorized to use cron/
233
- raise FileReadError, _("User %{path} not authorized to use cron") % { path: @path }, detail.backtrace
271
+ Puppet.debug _("The %{path} user is not authorized to use cron. Their crontab file is treated as empty in case Puppet authorizes them in the middle of the run (by, for example, modifying the cron.deny or cron.allow files).") % { path: @path }
272
+
273
+ return ""
234
274
  else
235
275
  raise FileReadError, _("Could not read crontab for %{path}: %{detail}") % { path: @path, detail: detail }, detail.backtrace
236
276
  end
@@ -267,13 +307,21 @@ class Puppet::Util::FileType
267
307
  newfiletype(:aixtab) do
268
308
  # Read a specific @path's cron tab.
269
309
  def read
310
+ unless Puppet::Util.uid(@path)
311
+ Puppet.debug _("The %{path} user does not exist. Treating their crontab file as empty in case Puppet creates them in the middle of the run.") % { path: @path }
312
+
313
+ return ""
314
+ end
315
+
270
316
  Puppet::Util::Execution.execute(%w{crontab -l}, cronargs)
271
317
  rescue => detail
272
318
  case detail.to_s
273
- when /Cannot open a file in the .* directory/
319
+ when /open.*in.*directory/
320
+ return ""
321
+ when /not.*authorized.*cron/
322
+ Puppet.debug _("The %{path} user is not authorized to use cron. Their crontab file is treated as empty in case Puppet authorizes them in the middle of the run (by, for example, modifying the cron.deny or cron.allow files).") % { path: @path }
323
+
274
324
  return ""
275
- when /You are not authorized to use the cron command/
276
- raise FileReadError, _("User %{path} not authorized to use cron") % { path: @path }, detail.backtrace
277
325
  else
278
326
  raise FileReadError, _("Could not read crontab for %{path}: %{detail}") % { path: @path, detail: detail }, detail.backtrace
279
327
  end
@@ -77,9 +77,10 @@ Puppet::Util::Log.newdesttype :file do
77
77
 
78
78
  # create the log file, if it doesn't already exist
79
79
  need_array_start = false
80
+ file_exists = File.exists?(path)
80
81
  if @json == 1
81
82
  need_array_start = true
82
- if File.exists?(path)
83
+ if file_exists
83
84
  sz = File.size(path)
84
85
  need_array_start = sz == 0
85
86
 
@@ -93,7 +94,7 @@ Puppet::Util::Log.newdesttype :file do
93
94
  file.puts('[') if need_array_start
94
95
 
95
96
  # Give ownership to the user and group puppet will run as
96
- if Puppet.features.root? && !Puppet::Util::Platform.windows?
97
+ if Puppet.features.root? && !Puppet::Util::Platform.windows? && !file_exists
97
98
  begin
98
99
  FileUtils.chown(Puppet[:user], Puppet[:group], path)
99
100
  rescue ArgumentError, Errno::EPERM
@@ -49,12 +49,13 @@ module Logging
49
49
  # to take advantage of the backtrace logging.
50
50
  def log_exception(exception, message = :default, options = {})
51
51
  trace = Puppet[:trace] || options[:trace]
52
+ level = options[:level] || :err
52
53
  if message == :default && exception.is_a?(Puppet::ParseErrorWithIssue)
53
54
  # Retain all detailed info and keep plain message and stacktrace separate
54
55
  backtrace = []
55
56
  build_exception_trace(backtrace, exception, trace)
56
57
  Puppet::Util::Log.create({
57
- :level => options[:level] || :err,
58
+ :level => level,
58
59
  :source => log_source,
59
60
  :message => exception.basic_message,
60
61
  :issue_code => exception.issue_code,
@@ -66,7 +67,7 @@ module Logging
66
67
  :node => exception.node
67
68
  }.merge(log_metadata))
68
69
  else
69
- err(format_exception(exception, message, trace))
70
+ send_log(level, format_exception(exception, message, trace))
70
71
  end
71
72
  end
72
73
 
@@ -9,7 +9,22 @@ module Puppet::Util::POSIX
9
9
  # environment for "exec" runs
10
10
  USER_ENV_VARS = ['HOME', 'USER', 'LOGNAME']
11
11
 
12
+ class << self
13
+ # Returns an array of all the groups that the user's a member of.
14
+ def groups_of(user)
15
+ groups = []
16
+ Puppet::Etc.group do |group|
17
+ groups << group.name if group.mem.include?(user)
18
+ end
19
+
20
+ uniq_groups = groups.uniq
21
+ if uniq_groups != groups
22
+ Puppet.debug(_('Removing any duplicate group entries'))
23
+ end
12
24
 
25
+ uniq_groups
26
+ end
27
+ end
13
28
 
14
29
  # Retrieve a field from a POSIX Etc object. The id can be either an integer
15
30
  # or a name. This only works for users and groups. It's also broken on
@@ -190,7 +190,7 @@ module Puppet::Util::SELinux
190
190
  def selinux_label_support?(file)
191
191
  fstype = find_fs(file)
192
192
  return false if fstype.nil?
193
- filesystems = ['ext2', 'ext3', 'ext4', 'gfs', 'gfs2', 'xfs', 'jfs', 'btrfs']
193
+ filesystems = ['ext2', 'ext3', 'ext4', 'gfs', 'gfs2', 'xfs', 'jfs', 'btrfs', 'tmpfs']
194
194
  filesystems.include?(fstype)
195
195
  end
196
196
 
@@ -82,6 +82,18 @@ class Puppet::Util::Storage
82
82
 
83
83
  Puppet.info _("Creating state file %{file}") % { file: Puppet[:statefile] } unless Puppet::FileSystem.exist?(Puppet[:statefile])
84
84
 
85
+ if Puppet[:statettl] == 0 || Puppet[:statettl] == Float::INFINITY
86
+ Puppet.debug "Not pruning old state cache entries"
87
+ else
88
+ Puppet::Util.benchmark(:debug, "Pruned old state cache entries in %{seconds} seconds") do
89
+ ttl_cutoff = Time.now - Puppet[:statettl]
90
+
91
+ @@state.reject! do |k,v|
92
+ @@state[k][:checked] && @@state[k][:checked] < ttl_cutoff
93
+ end
94
+ end
95
+ end
96
+
85
97
  Puppet::Util.benchmark(:debug, "Stored state in %{seconds} seconds") do
86
98
  Puppet::Util::Yaml.dump(@@state, Puppet[:statefile])
87
99
  end
@@ -134,7 +134,7 @@ module Puppet::Util::Windows::ADSI
134
134
 
135
135
  def parse_name(name)
136
136
  if name =~ /\//
137
- raise Puppet::Error.new( _("Value must be in DOMAIN\\user style syntax") )
137
+ raise Puppet::Error.new( _("Value must be in DOMAIN\\%{object_class} style syntax") % { object_class: @object_class } )
138
138
  end
139
139
 
140
140
  matches = name.scan(/((.*)\\)?(.*)/)
@@ -250,7 +250,7 @@ module Puppet::Util::Windows::ADSI
250
250
  # ERROR_BAD_USERNAME 2202L from winerror.h
251
251
  if e.message =~ /8007089A/m
252
252
  raise Puppet::Error.new(
253
- _("Puppet is not able to create/delete domain %{object_class}s with the %{object_class} resource.") % { object_class: object_class },
253
+ _("Puppet is not able to create/delete domain %{object_class} objects with the %{object_class} resource.") % { object_class: object_class },
254
254
  )
255
255
  end
256
256
 
@@ -376,6 +376,83 @@ module Puppet::Util::Windows::ADSI
376
376
  end
377
377
  end
378
378
 
379
+ # Declare all of the available user flags on the system. Note that
380
+ # ADS_UF is read as ADS_UserFlag
381
+ # https://docs.microsoft.com/en-us/windows/desktop/api/iads/ne-iads-ads_user_flag
382
+ # and
383
+ # https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro
384
+ # for the flag values.
385
+ ADS_USERFLAGS = {
386
+ ADS_UF_SCRIPT: 0x0001,
387
+ ADS_UF_ACCOUNTDISABLE: 0x0002,
388
+ ADS_UF_HOMEDIR_REQUIRED: 0x0008,
389
+ ADS_UF_LOCKOUT: 0x0010,
390
+ ADS_UF_PASSWD_NOTREQD: 0x0020,
391
+ ADS_UF_PASSWD_CANT_CHANGE: 0x0040,
392
+ ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED: 0x0080,
393
+ ADS_UF_TEMP_DUPLICATE_ACCOUNT: 0x0100,
394
+ ADS_UF_NORMAL_ACCOUNT: 0x0200,
395
+ ADS_UF_INTERDOMAIN_TRUST_ACCOUNT: 0x0800,
396
+ ADS_UF_WORKSTATION_TRUST_ACCOUNT: 0x1000,
397
+ ADS_UF_SERVER_TRUST_ACCOUNT: 0x2000,
398
+ ADS_UF_DONT_EXPIRE_PASSWD: 0x10000,
399
+ ADS_UF_MNS_LOGON_ACCOUNT: 0x20000,
400
+ ADS_UF_SMARTCARD_REQUIRED: 0x40000,
401
+ ADS_UF_TRUSTED_FOR_DELEGATION: 0x80000,
402
+ ADS_UF_NOT_DELEGATED: 0x100000,
403
+ ADS_UF_USE_DES_KEY_ONLY: 0x200000,
404
+ ADS_UF_DONT_REQUIRE_PREAUTH: 0x400000,
405
+ ADS_UF_PASSWORD_EXPIRED: 0x800000,
406
+ ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION: 0x1000000
407
+ }
408
+
409
+ def userflag_set?(flag)
410
+ flag_value = ADS_USERFLAGS[flag] || 0
411
+ ! (self['UserFlags'] & flag_value).zero?
412
+ end
413
+
414
+ # Common helper for set_userflags and unset_userflags.
415
+ #
416
+ # @api private
417
+ def op_userflags(*flags, &block)
418
+ # Avoid an unnecessary set + commit operation.
419
+ return if flags.empty?
420
+
421
+ unrecognized_flags = flags.reject { |flag| ADS_USERFLAGS.keys.include?(flag) }
422
+ unless unrecognized_flags.empty?
423
+ raise ArgumentError, _("Unrecognized ADS UserFlags: %{unrecognized_flags}") % { unrecognized_flags: unrecognized_flags.join(', ') }
424
+ end
425
+
426
+ self['UserFlags'] = flags.inject(self['UserFlags'], &block)
427
+ end
428
+
429
+ def set_userflags(*flags)
430
+ op_userflags(*flags) { |userflags, flag| userflags | ADS_USERFLAGS[flag] }
431
+ end
432
+
433
+ def unset_userflags(*flags)
434
+ op_userflags(*flags) { |userflags, flag| userflags & ~ADS_USERFLAGS[flag] }
435
+ end
436
+
437
+ def disabled?
438
+ userflag_set?(:ADS_UF_ACCOUNTDISABLE)
439
+ end
440
+
441
+ def locked_out?
442
+ # Note that the LOCKOUT flag is known to be inaccurate when using the
443
+ # LDAP IADsUser provider, but this class consistently uses the WinNT
444
+ # provider, which is expected to be accurate.
445
+ userflag_set?(:ADS_UF_LOCKOUT)
446
+ end
447
+
448
+ def expired?
449
+ expires = native_object.Get('AccountExpirationDate')
450
+ expires && expires < Time.now
451
+ rescue WIN32OLERuntimeError => e
452
+ # This OLE error code indicates the property can't be found in the cache
453
+ raise e unless e.message =~ /8000500D/m
454
+ false
455
+ end
379
456
 
380
457
  # UNLEN from lmcons.h - https://stackoverflow.com/a/2155176
381
458
  MAX_USERNAME_LENGTH = 256
@@ -58,7 +58,7 @@ module Puppet::Util::Windows::APITypes
58
58
  str = get_bytes(0, char_length * 2).force_encoding('UTF-16LE')
59
59
  str.encode(dst_encoding, str.encoding, encode_options)
60
60
  rescue Exception => e
61
- Puppet.debug "Unable to convert value #{str.dump} to encoding #{dst_encoding} due to #{e.inspect}"
61
+ Puppet.debug "Unable to convert value #{str.nil? ? 'nil' : str.dump} to encoding #{dst_encoding} due to #{e.inspect}"
62
62
  raise
63
63
  end
64
64
 
@@ -7,15 +7,35 @@ module Puppet::Util::Windows::Process
7
7
  extend FFI::Library
8
8
 
9
9
  WAIT_TIMEOUT = 0x102
10
+ WAIT_INTERVAL = 200
11
+ # https://docs.microsoft.com/en-us/windows/desktop/ProcThread/process-creation-flags
12
+ CREATE_NO_WINDOW = 0x08000000
10
13
 
11
14
  def execute(command, arguments, stdin, stdout, stderr)
12
- Process.create( :command_line => command, :startup_info => {:stdin => stdin, :stdout => stdout, :stderr => stderr}, :close_handles => false )
15
+ create_args = {
16
+ :command_line => command,
17
+ :startup_info => {
18
+ :stdin => stdin,
19
+ :stdout => stdout,
20
+ :stderr => stderr
21
+ },
22
+ :close_handles => false,
23
+ }
24
+ if arguments[:suppress_window]
25
+ create_args[:creation_flags] = CREATE_NO_WINDOW
26
+ end
27
+ cwd = arguments[:cwd]
28
+ if cwd
29
+ Dir.chdir(cwd) { Process.create(create_args) }
30
+ else
31
+ Process.create(create_args)
32
+ end
13
33
  end
14
34
  module_function :execute
15
35
 
16
36
  def wait_process(handle)
17
- while WaitForSingleObject(handle, 0) == WAIT_TIMEOUT
18
- sleep(1)
37
+ while WaitForSingleObject(handle, WAIT_INTERVAL) == WAIT_TIMEOUT
38
+ sleep(0)
19
39
  end
20
40
 
21
41
  exit_status = -1
@@ -65,6 +65,28 @@ module Puppet::Util::Windows
65
65
  vals
66
66
  end
67
67
 
68
+ # Retrieve a set of values from a registry key given their names
69
+ # Value names listed but not found in the registry will not be added to the
70
+ # resultant Hashtable
71
+ #
72
+ # @param key [RegistryKey] An open handle to a Registry Key
73
+ # @param names [String[]] An array of names of registry values to return if they exist
74
+ # @return [Hashtable<String, Object>] A hashtable of all of the found values in the registry key
75
+ def values_by_name(key, names)
76
+ vals = {}
77
+ names.each do |name|
78
+ FFI::Pointer.from_string_to_wide_string(name) do |subkeyname_ptr|
79
+ begin
80
+ _, vals[name] = read(key, subkeyname_ptr)
81
+ rescue Puppet::Util::Windows::Error => e
82
+ # ignore missing names, but raise other errors
83
+ raise e unless e.code == Puppet::Util::Windows::Error::ERROR_FILE_NOT_FOUND
84
+ end
85
+ end
86
+ end
87
+ vals
88
+ end
89
+
68
90
  def each_value(key, &block)
69
91
  index = 0
70
92
  subkey = nil
@@ -104,7 +126,7 @@ module Puppet::Util::Windows
104
126
 
105
127
  if result != FFI::ERROR_SUCCESS
106
128
  msg = _("Failed to enumerate %{key} registry keys at index %{index}") % { key: key.keyname, index: index }
107
- raise Puppet::Util::Windows::Error.new(msg)
129
+ raise Puppet::Util::Windows::Error.new(msg, result)
108
130
  end
109
131
 
110
132
  filetime = FFI::WIN32::FILETIME.new(filetime_ptr)
@@ -135,7 +157,7 @@ module Puppet::Util::Windows
135
157
 
136
158
  if result != FFI::ERROR_SUCCESS
137
159
  msg = _("Failed to enumerate %{key} registry values at index %{index}") % { key: key.keyname, index: index }
138
- raise Puppet::Util::Windows::Error.new(msg)
160
+ raise Puppet::Util::Windows::Error.new(msg, result)
139
161
  end
140
162
 
141
163
  subkey_length = subkey_length_ptr.read_dword
@@ -165,7 +187,7 @@ module Puppet::Util::Windows
165
187
 
166
188
  if status != FFI::ERROR_SUCCESS
167
189
  msg = _("Failed to query registry %{key} for sizes") % { key: key.keyname }
168
- raise Puppet::Util::Windows::Error.new(msg)
190
+ raise Puppet::Util::Windows::Error.new(msg, status)
169
191
  end
170
192
 
171
193
  result = [
@@ -247,8 +269,10 @@ module Puppet::Util::Windows
247
269
  buffer_ptr, length_ptr)
248
270
 
249
271
  if result != FFI::ERROR_SUCCESS
250
- msg = _("Failed to read registry value %{value} at %{key}") % { value: name_ptr.read_wide_string, key: key.keyname }
251
- raise Puppet::Util::Windows::Error.new(msg)
272
+ # buffer is raw bytes, *not* chars - less a NULL terminator
273
+ name_length = (name_ptr.size / FFI.type_size(:wchar)) - 1 if name_ptr.size > 0
274
+ msg = _("Failed to read registry value %{value} at %{key}") % { value: name_ptr.read_wide_string(name_length), key: key.keyname }
275
+ raise Puppet::Util::Windows::Error.new(msg, result)
252
276
  end
253
277
 
254
278
  # allows caller to use FFI MemoryPointer helpers to read / shape
@@ -324,6 +324,20 @@ module Puppet::Util::Windows::Security
324
324
  # we don't check S_ISYSTEM_MISSING bit, but automatically carry over existing SYSTEM perms
325
325
  # by default set SYSTEM perms to full
326
326
  system_allow = FILE::FILE_ALL_ACCESS
327
+ else
328
+ # It is possible to set SYSTEM with a mode other than Full Control (7) however this makes no sense and in practical terms
329
+ # should not be done. We can trap these instances and correct them before being applied.
330
+ 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
334
+ end
335
+
336
+ 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
340
+ end
327
341
  end
328
342
 
329
343
  # even though FILE_DELETE_CHILD only applies to directories, it can be set on files