puppet 4.10.10 → 4.10.11

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 (84) hide show
  1. data/CONTRIBUTING.md +15 -15
  2. data/Gemfile +3 -0
  3. data/README.md +11 -11
  4. data/ext/project_data.yaml +4 -2
  5. data/lib/puppet/application/agent.rb +1 -3
  6. data/lib/puppet/application/apply.rb +1 -3
  7. data/lib/puppet/application/cert.rb +6 -1
  8. data/lib/puppet/application/lookup.rb +11 -1
  9. data/lib/puppet/configurer.rb +17 -4
  10. data/lib/puppet/environments.rb +1 -1
  11. data/lib/puppet/functions/map.rb +1 -1
  12. data/lib/puppet/indirector/indirection.rb +3 -3
  13. data/lib/puppet/indirector/request.rb +6 -2
  14. data/lib/puppet/network/http/connection.rb +8 -0
  15. data/lib/puppet/parser/functions/new.rb +29 -44
  16. data/lib/puppet/parser/functions/return.rb +22 -1
  17. data/lib/puppet/pops/resource/resource_type_impl.rb +1 -1
  18. data/lib/puppet/provider/group/windows_adsi.rb +4 -7
  19. data/lib/puppet/provider/package/dnf.rb +1 -1
  20. data/lib/puppet/provider/service/systemd.rb +1 -1
  21. data/lib/puppet/provider/user/aix.rb +1 -1
  22. data/lib/puppet/provider/user/windows_adsi.rb +1 -1
  23. data/lib/puppet/reference/configuration.rb +2 -0
  24. data/lib/puppet/type/tidy.rb +8 -1
  25. data/lib/puppet/type/user.rb +34 -3
  26. data/lib/puppet/util/reference.rb +2 -9
  27. data/lib/puppet/util/windows/adsi.rb +28 -31
  28. data/lib/puppet/util/windows/file.rb +61 -9
  29. data/lib/puppet/util/windows/principal.rb +9 -7
  30. data/lib/puppet/util/windows/sid.rb +60 -7
  31. data/lib/puppet/version.rb +1 -1
  32. data/locales/puppet.pot +79 -11
  33. data/man/man5/puppet.conf.5 +6 -8
  34. data/man/man8/extlookup2hiera.8 +1 -1
  35. data/man/man8/puppet-agent.8 +1 -1
  36. data/man/man8/puppet-apply.8 +1 -1
  37. data/man/man8/puppet-ca.8 +1 -1
  38. data/man/man8/puppet-catalog.8 +1 -1
  39. data/man/man8/puppet-cert.8 +1 -1
  40. data/man/man8/puppet-certificate.8 +1 -1
  41. data/man/man8/puppet-certificate_request.8 +1 -1
  42. data/man/man8/puppet-certificate_revocation_list.8 +1 -1
  43. data/man/man8/puppet-config.8 +1 -1
  44. data/man/man8/puppet-describe.8 +1 -1
  45. data/man/man8/puppet-device.8 +1 -1
  46. data/man/man8/puppet-doc.8 +1 -1
  47. data/man/man8/puppet-epp.8 +1 -1
  48. data/man/man8/puppet-facts.8 +1 -1
  49. data/man/man8/puppet-file.8 +1 -1
  50. data/man/man8/puppet-filebucket.8 +1 -1
  51. data/man/man8/puppet-generate.8 +1 -1
  52. data/man/man8/puppet-help.8 +1 -1
  53. data/man/man8/puppet-inspect.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-master.8 +1 -1
  58. data/man/man8/puppet-module.8 +1 -1
  59. data/man/man8/puppet-node.8 +1 -1
  60. data/man/man8/puppet-parser.8 +1 -1
  61. data/man/man8/puppet-plugin.8 +1 -1
  62. data/man/man8/puppet-report.8 +1 -1
  63. data/man/man8/puppet-resource.8 +1 -1
  64. data/man/man8/puppet-resource_type.8 +1 -1
  65. data/man/man8/puppet-status.8 +1 -1
  66. data/man/man8/puppet.8 +2 -2
  67. data/spec/integration/application/lookup_spec.rb +21 -0
  68. data/spec/integration/parser/pcore_resource_spec.rb +1 -1
  69. data/spec/integration/util/windows/adsi_spec.rb +86 -1
  70. data/spec/integration/util/windows/principal_spec.rb +10 -1
  71. data/spec/unit/application/agent_spec.rb +0 -9
  72. data/spec/unit/application/apply_spec.rb +0 -9
  73. data/spec/unit/application/cert_spec.rb +40 -1
  74. data/spec/unit/configurer_spec.rb +14 -0
  75. data/spec/unit/indirector/indirection_spec.rb +24 -2
  76. data/spec/unit/provider/group/windows_adsi_spec.rb +79 -22
  77. data/spec/unit/provider/service/systemd_spec.rb +1 -1
  78. data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
  79. data/spec/unit/type/tidy_spec.rb +14 -0
  80. data/spec/unit/util/windows/adsi_spec.rb +31 -27
  81. data/spec/unit/util/windows/sid_spec.rb +86 -15
  82. data/tasks/manpages.rake +1 -1
  83. metadata +3621 -3609
  84. checksums.yaml +0 -7
@@ -4,7 +4,8 @@ Puppet::Parser::Functions::newfunction(
4
4
  :doc => <<-DOC
5
5
  Immediately returns the given optional value from a function, class body or user defined type body.
6
6
  If a value is not given, an `undef` value is returned. This function does not return to the immediate caller.
7
- If called from within a lambda the return will return from the function evaluating the lambda.
7
+ If this function is called from within a lambda, the return action is from the scope of the
8
+ function containing the lambda (top scope), not the function accepting the lambda (local scope).
8
9
 
9
10
  The signal produced to return a value bubbles up through
10
11
  the call stack until reaching a function, class definition or
@@ -63,6 +64,26 @@ The code would notice `'bar'` but not `'foo'`
63
64
 
64
65
  Note that the returned value is ignored if used in a class or user defined type.
65
66
 
67
+ **Example:** Using `return` in a lambda
68
+
69
+ ```puppet
70
+ # Concatenate three strings into a single string formatted as a list.
71
+ function getFruit() {
72
+ with("apples", "oranges", "bananas") |$x, $y, $z| {
73
+ return("${x}, ${y}, and ${z}")
74
+ }
75
+ notice "not reached"
76
+ }
77
+ $fruit = getFruit()
78
+ notice $fruit
79
+
80
+ # The output contains "apples, oranges, and bananas".
81
+ # "not reached" is not output because the function returns its value within the
82
+ # calling function's scope, which stops processing the calling function before
83
+ # the `notice "not reached"` statement.
84
+ # Using `return()` outside of a calling function results in an error.
85
+ ```
86
+
66
87
  * Also see functions `return` and `break`
67
88
  * Since 4.8.0
68
89
  DOC
@@ -149,7 +149,7 @@ class ResourceTypeImpl
149
149
  # Here it is silently ignored.
150
150
  nil
151
151
  when 1
152
- if @title_pattners_hash.nil?
152
+ if @title_patterns_hash.nil?
153
153
  [ [ /(.*)/m, [ [@key_attributes.first] ] ] ]
154
154
  else
155
155
  # TechDebt: The case of having one namevar and an empty title patterns is unspecified behavior in puppet.
@@ -23,12 +23,9 @@ Puppet::Type.type(:group).provide :windows_adsi do
23
23
  # Cannot use munge of the group property to canonicalize @should
24
24
  # since the default array_matching comparison is not commutative
25
25
 
26
+ current_sids = current.map(&:sid)
26
27
  # dupes automatically weeded out when hashes built
27
- current_users = Puppet::Util::Windows::ADSI::Group.name_sid_hash(current)
28
- specified_users = Puppet::Util::Windows::ADSI::Group.name_sid_hash(should)
29
-
30
- current_sids = current_users.keys.to_a
31
- specified_sids = specified_users.keys.to_a
28
+ specified_sids = Puppet::Util::Windows::ADSI::Group.name_sid_hash(should).keys.to_a
32
29
 
33
30
  if @resource[:auth_membership]
34
31
  current_sids.sort == specified_sids.sort
@@ -40,7 +37,7 @@ Puppet::Type.type(:group).provide :windows_adsi do
40
37
  def members_to_s(users)
41
38
  return '' if users.nil? or !users.kind_of?(Array)
42
39
  users = users.map do |user_name|
43
- sid = Puppet::Util::Windows::SID.name_to_sid_object(user_name)
40
+ sid = Puppet::Util::Windows::SID.name_to_principal(user_name)
44
41
  if !sid
45
42
  resource.debug("#{user_name} (unresolvable to SID)")
46
43
  next user_name
@@ -58,7 +55,7 @@ Puppet::Type.type(:group).provide :windows_adsi do
58
55
  end
59
56
 
60
57
  def member_valid?(user_name)
61
- ! Puppet::Util::Windows::SID.name_to_sid_object(user_name).nil?
58
+ ! Puppet::Util::Windows::SID.name_to_principal(user_name).nil?
62
59
  end
63
60
 
64
61
  def group
@@ -28,7 +28,7 @@ Puppet::Type.type(:package).provide :dnf, :parent => :yum do
28
28
  end
29
29
  end
30
30
 
31
- defaultfor :operatingsystem => :fedora, :operatingsystemmajrelease => ['22', '23', '24', '25']
31
+ defaultfor :operatingsystem => :fedora, :operatingsystemmajrelease => (22..30).to_a
32
32
 
33
33
  def self.update_command
34
34
  # In DNF, update is deprecated for upgrade
@@ -25,7 +25,7 @@ Puppet::Type.type(:service).provide :systemd, :parent => :base do
25
25
  defaultfor :osfamily => :coreos
26
26
  defaultfor :operatingsystem => :amazon, :operatingsystemmajrelease => ["2"]
27
27
  defaultfor :operatingsystem => :debian, :operatingsystemmajrelease => ["8", "stretch/sid", "9", "buster/sid"]
28
- defaultfor :operatingsystem => :ubuntu, :operatingsystemmajrelease => ["15.04","15.10","16.04","16.10"]
28
+ defaultfor :operatingsystem => :ubuntu, :operatingsystemmajrelease => ["15.04","15.10","16.04","16.10","17.04","17.10"]
29
29
  defaultfor :operatingsystem => :cumuluslinux, :operatingsystemmajrelease => ["3"]
30
30
 
31
31
  def self.instances
@@ -268,7 +268,7 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do
268
268
  # Must receive "user:enc_password" as input
269
269
  # command, arguments = {:failonfail => true, :combine => true}
270
270
  # Fix for bugs #11200 and #10915
271
- cmd = [self.class.command(:chpasswd), get_ia_module_args, '-e', '-c', user].flatten
271
+ cmd = [self.class.command(:chpasswd), get_ia_module_args, '-e', '-c'].flatten
272
272
  begin
273
273
  output = execute(cmd, {:failonfail => false, :combine => true, :stdinfile => tmpfile.path })
274
274
  # chpasswd can return 1, even on success (at least on AIX 6.1); empty output indicates success
@@ -52,7 +52,7 @@ Puppet::Type.type(:user).provide :windows_adsi do
52
52
  def groups_to_s(groups)
53
53
  return '' if groups.nil? || !groups.kind_of?(Array)
54
54
  groups = groups.map do |group_name|
55
- sid = Puppet::Util::Windows::SID.name_to_sid_object(group_name)
55
+ sid = Puppet::Util::Windows::SID.name_to_principal(group_name)
56
56
  if sid.account =~ /\\/
57
57
  account, _ = Puppet::Util::Windows::ADSI::Group.parse_name(sid.account)
58
58
  else
@@ -34,6 +34,8 @@ config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc
34
34
  val = 'Unix/Linux: /var/log/puppetlabs/puppet -- Windows: C:\ProgramData\PuppetLabs\puppet\var\log -- Non-root user: ~/.puppetlabs/var/log'
35
35
  elsif name.to_s == 'hiera_config'
36
36
  val = '$confdir/hiera.yaml. However, if a file exists at $codedir/hiera.yaml, Puppet uses that instead.'
37
+ elsif name.to_s == 'certname'
38
+ val = "the Host's fully qualified domain name, as determined by facter"
37
39
  end
38
40
 
39
41
  # Leave out the section information; it was apparently confusing people.
@@ -222,7 +222,14 @@ Puppet::Type.newtype(:tidy) do
222
222
  # Make a file resource to remove a given file.
223
223
  def mkfile(path)
224
224
  # Force deletion, so directories actually get deleted.
225
- Puppet::Type.type(:file).new :path => path, :backup => self[:backup], :ensure => :absent, :force => true
225
+ parameters = {
226
+ :path => path, :backup => self[:backup],
227
+ :ensure => :absent, :force => true
228
+ }
229
+
230
+ parameters[:noop] = self[:noop] unless self[:noop].nil?
231
+
232
+ Puppet::Type.type(:file).new(parameters)
226
233
  end
227
234
 
228
235
  def retrieve
@@ -212,13 +212,44 @@ module Puppet
212
212
  * OS X 10.8 and higher use salted SHA512 PBKDF2 hashes. When managing passwords
213
213
  on these systems, the `salt` and `iterations` attributes need to be specified as
214
214
  well as the password.
215
- * Windows passwords can only be managed in cleartext, as there is no Windows API
216
- for setting the password hash.
215
+ * Windows passwords can be managed only in cleartext, because there is no Windows
216
+ API for setting the password hash.
217
217
 
218
218
  [stdlib]: https://github.com/puppetlabs/puppetlabs-stdlib/
219
219
 
220
220
  Enclose any value that includes a dollar sign ($) in single quotes (') to avoid
221
- accidental variable interpolation.}
221
+ accidental variable interpolation.
222
+
223
+ To redact passwords from reports to PuppetDB, use the `Sensitive` data type. For
224
+ example, this resource protects the password:
225
+
226
+ ```puppet
227
+ user { 'foo':
228
+ ensure => present,
229
+ password => Sensitive("my secret password")
230
+ }
231
+ ```
232
+
233
+ This results in the password being redacted from the report, as in the
234
+ `previous_value`, `desired_value`, and `message` fields below.
235
+
236
+ ```yaml
237
+ events:
238
+ - !ruby/object:Puppet::Transaction::Event
239
+ audited: false
240
+ property: password
241
+ previous_value: "[redacted]"
242
+ desired_value: "[redacted]"
243
+ historical_value:
244
+ message: changed [redacted] to [redacted]
245
+ name: :password_changed
246
+ status: success
247
+ time: 2017-05-17 16:06:02.934398293 -07:00
248
+ redacted: true
249
+ corrective_change: false
250
+ corrective_change: false
251
+ ```
252
+ }
222
253
 
223
254
  validate do |value|
224
255
  raise ArgumentError, "Passwords cannot include ':'" if value.is_a?(String) and value.include?(":")
@@ -12,11 +12,6 @@ class Puppet::Util::Reference
12
12
 
13
13
  instance_load(:reference, 'puppet/reference')
14
14
 
15
- def self.footer
16
- #TRANSLATORS message accompanied by date of generation
17
- "\n\n----------------\n\n*" + _("This page autogenerated on ") + "#{Time.now}*\n"
18
- end
19
-
20
15
  def self.modes
21
16
  %w{pdf text}
22
17
  end
@@ -112,15 +107,13 @@ class Puppet::Util::Reference
112
107
  def to_markdown(withcontents = true)
113
108
  # First the header
114
109
  text = markdown_header(@title, 1)
115
- #TRANSLATORS message accompanied by date of generation
116
- text << _("\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on ") + "#{Time.now.to_s})*\n\n"
110
+
111
+ text << _("\n\n**This page is autogenerated; any changes will get overwritten**\n\n")
117
112
 
118
113
  text << @header
119
114
 
120
115
  text << generate
121
116
 
122
- text << self.class.footer if withcontents
123
-
124
117
  text
125
118
  end
126
119
  end
@@ -16,7 +16,7 @@ module Puppet::Util::Windows::ADSI
16
16
  begin
17
17
  WIN32OLE.connect(uri)
18
18
  rescue WIN32OLERuntimeError => e
19
- raise Puppet::Error.new( "ADSI connection error: #{e}", e )
19
+ raise Puppet::Error.new( _("ADSI connection error: %{e}") % { e: e }, e )
20
20
  end
21
21
  end
22
22
 
@@ -39,7 +39,7 @@ module Puppet::Util::Windows::ADSI
39
39
  buffer_size.write_dword(max_length) # length in TCHARs
40
40
 
41
41
  if GetComputerNameW(buffer, buffer_size) == FFI::WIN32_FALSE
42
- raise Puppet::Util::Windows::Error.new("Failed to get computer name")
42
+ raise Puppet::Util::Windows::Error.new(_("Failed to get computer name"))
43
43
  end
44
44
  @computer_name = buffer.read_wide_string(buffer_size.read_dword)
45
45
  end
@@ -66,7 +66,7 @@ module Puppet::Util::Windows::ADSI
66
66
  return sid_uri(sid) if sid.kind_of?(Puppet::Util::Windows::SID::Principal)
67
67
 
68
68
  begin
69
- sid = Puppet::Util::Windows::SID.name_to_sid_object(sid)
69
+ sid = Puppet::Util::Windows::SID.name_to_principal(sid)
70
70
  sid_uri(sid)
71
71
  rescue Puppet::Util::Windows::Error, Puppet::Error
72
72
  nil
@@ -77,7 +77,7 @@ module Puppet::Util::Windows::ADSI
77
77
  # used for IAdsGroup::Add / IAdsGroup::Remove. These URIs are not useable
78
78
  # to resolve an account with WIN32OLE.connect
79
79
  def sid_uri(sid)
80
- raise Puppet::Error.new( "Must use a valid SID::Principal" ) if !sid.kind_of?(Puppet::Util::Windows::SID::Principal)
80
+ raise Puppet::Error.new( _("Must use a valid SID::Principal") ) if !sid.kind_of?(Puppet::Util::Windows::SID::Principal)
81
81
 
82
82
  "WinNT://#{sid.sid}"
83
83
  end
@@ -114,7 +114,7 @@ module Puppet::Util::Windows::ADSI
114
114
  Puppet::Util::Windows::SID.sid_to_name('S-1-5-32').upcase,
115
115
  # localized version of NT AUTHORITY (can't use S-1-5)
116
116
  # for instance AUTORITE NT on French Windows
117
- Puppet::Util::Windows::SID.name_to_sid_object('SYSTEM').domain.upcase
117
+ Puppet::Util::Windows::SID.name_to_principal('SYSTEM').domain.upcase
118
118
  ]
119
119
  end
120
120
 
@@ -129,7 +129,7 @@ module Puppet::Util::Windows::ADSI
129
129
 
130
130
  def parse_name(name)
131
131
  if name =~ /\//
132
- raise Puppet::Error.new( "Value must be in DOMAIN\\user style syntax" )
132
+ raise Puppet::Error.new( _("Value must be in DOMAIN\\user style syntax") )
133
133
  end
134
134
 
135
135
  matches = name.scan(/((.*)\\)?(.*)/)
@@ -139,10 +139,12 @@ module Puppet::Util::Windows::ADSI
139
139
  return account, domain
140
140
  end
141
141
 
142
+ # returns Puppet::Util::Windows::SID::Principal[]
143
+ # may contain objects that represent unresolvable SIDs
142
144
  def get_sids(adsi_child_collection)
143
145
  sids = []
144
146
  adsi_child_collection.each do |m|
145
- sids << Puppet::Util::Windows::SID.octet_string_to_sid_object(m.objectSID)
147
+ sids << Puppet::Util::Windows::SID.ads_to_principal(m)
146
148
  end
147
149
 
148
150
  sids
@@ -152,8 +154,8 @@ module Puppet::Util::Windows::ADSI
152
154
  return {} if names.nil? || names.empty?
153
155
 
154
156
  sids = names.map do |name|
155
- sid = Puppet::Util::Windows::SID.name_to_sid_object(name)
156
- raise Puppet::Error.new( "Could not resolve name: #{name}" ) if !sid
157
+ sid = Puppet::Util::Windows::SID.name_to_principal(name)
158
+ raise Puppet::Error.new( _("Could not resolve name: %{name}") % { name: name } ) if !sid
157
159
  [sid.sid, sid]
158
160
  end
159
161
 
@@ -183,7 +185,7 @@ module Puppet::Util::Windows::ADSI
183
185
  end
184
186
 
185
187
  def sid
186
- @sid ||= Puppet::Util::Windows::SID.octet_string_to_sid_object(native_user.objectSID)
188
+ @sid ||= Puppet::Util::Windows::SID.octet_string_to_principal(native_user.objectSID)
187
189
  end
188
190
 
189
191
  def uri
@@ -211,12 +213,12 @@ module Puppet::Util::Windows::ADSI
211
213
  # ERROR_BAD_USERNAME 2202L from winerror.h
212
214
  if e.message =~ /8007089A/m
213
215
  raise Puppet::Error.new(
214
- "Puppet is not able to create/delete domain users with the user resource.",
216
+ _("Puppet is not able to create/delete domain users with the user resource."),
215
217
  e
216
218
  )
217
219
  end
218
220
 
219
- raise Puppet::Error.new( "User update failed: #{e}", e )
221
+ raise Puppet::Error.new( _("User update failed: %{e}") % { e: e }, e )
220
222
  end
221
223
  self
222
224
  end
@@ -311,7 +313,7 @@ module Puppet::Util::Windows::ADSI
311
313
 
312
314
  def self.create(name)
313
315
  # Windows error 1379: The specified local group already exists.
314
- raise Puppet::Error.new( "Cannot create user if group '#{name}' exists." ) if Puppet::Util::Windows::ADSI::Group.exists? name
316
+ raise Puppet::Error.new(_("Cannot create user if group '%{name}' exists.") % { name: name }) if Puppet::Util::Windows::ADSI::Group.exists? name
315
317
  new(name, Puppet::Util::Windows::ADSI.create(name, 'user'))
316
318
  end
317
319
 
@@ -325,7 +327,7 @@ module Puppet::Util::Windows::ADSI
325
327
  buffer_size.write_dword(max_length) # length in TCHARs
326
328
 
327
329
  if GetUserNameW(buffer, buffer_size) == FFI::WIN32_FALSE
328
- raise Puppet::Util::Windows::Error.new("Failed to get user name")
330
+ raise Puppet::Util::Windows::Error.new(_("Failed to get user name"))
329
331
  end
330
332
  # buffer_size includes trailing NULL
331
333
  user_name = buffer.read_wide_string(buffer_size.read_dword - 1)
@@ -336,12 +338,12 @@ module Puppet::Util::Windows::ADSI
336
338
  end
337
339
 
338
340
  def self.current_user_sid
339
- Puppet::Util::Windows::SID.name_to_sid_object(current_user_name)
341
+ Puppet::Util::Windows::SID.name_to_principal(current_user_name)
340
342
  end
341
343
 
342
344
  def self.exists?(name_or_sid)
343
345
  well_known = false
344
- if (sid = Puppet::Util::Windows::SID.name_to_sid_object(name_or_sid))
346
+ if (sid = Puppet::Util::Windows::SID.name_to_principal(name_or_sid))
345
347
  return true if sid.account_type == :SidTypeUser
346
348
 
347
349
  # 'well known group' is special as it can be a group like Everyone OR a user like SYSTEM
@@ -403,7 +405,7 @@ module Puppet::Util::Windows::ADSI
403
405
  # but warn if we fail
404
406
  raise e unless e.message.include?('80041010')
405
407
 
406
- Puppet.warning "Cannot delete user profile for '#{sid}' prior to Vista SP1"
408
+ Puppet.warning _("Cannot delete user profile for '%{sid}' prior to Vista SP1") % { sid: sid }
407
409
  end
408
410
  end
409
411
  end
@@ -431,7 +433,7 @@ module Puppet::Util::Windows::ADSI
431
433
  end
432
434
 
433
435
  def sid
434
- @sid ||= Puppet::Util::Windows::SID.octet_string_to_sid_object(native_group.objectSID)
436
+ @sid ||= Puppet::Util::Windows::SID.octet_string_to_principal(native_group.objectSID)
435
437
  end
436
438
 
437
439
  def commit
@@ -441,12 +443,12 @@ module Puppet::Util::Windows::ADSI
441
443
  # ERROR_BAD_USERNAME 2202L from winerror.h
442
444
  if e.message =~ /8007089A/m
443
445
  raise Puppet::Error.new(
444
- "Puppet is not able to create/delete domain groups with the group resource.",
446
+ _("Puppet is not able to create/delete domain groups with the group resource."),
445
447
  e
446
448
  )
447
449
  end
448
450
 
449
- raise Puppet::Error.new( "Group update failed: #{e}", e )
451
+ raise Puppet::Error.new( _("Group update failed: %{error}") % { error: e }, e )
450
452
  end
451
453
  self
452
454
  end
@@ -463,18 +465,13 @@ module Puppet::Util::Windows::ADSI
463
465
  end
464
466
  end
465
467
 
468
+ # returns Puppet::Util::Windows::SID::Principal[]
469
+ # may contain objects that represent unresolvable SIDs
470
+ # qualified account names are returned by calling #domain_account
466
471
  def members
467
- # WIN32OLE objects aren't enumerable, so no map
468
- members = []
469
- # Setting WIN32OLE.codepage in the microsoft_windows feature ensures
470
- # values are returned as UTF-8
471
- native_group.Members.each {|m| members << m.Name}
472
- members
473
- end
474
-
475
- def member_sids
476
472
  self.class.get_sids(native_group.Members)
477
473
  end
474
+ alias member_sids members
478
475
 
479
476
  def set_members(desired_members, inclusive = true)
480
477
  return if desired_members.nil?
@@ -502,13 +499,13 @@ module Puppet::Util::Windows::ADSI
502
499
 
503
500
  def self.create(name)
504
501
  # Windows error 2224: The account already exists.
505
- raise Puppet::Error.new( "Cannot create group if user '#{name}' exists." ) if Puppet::Util::Windows::ADSI::User.exists? name
502
+ raise Puppet::Error.new( _("Cannot create group if user '%{name}' exists.") % { name: name } ) if Puppet::Util::Windows::ADSI::User.exists? name
506
503
  new(name, Puppet::Util::Windows::ADSI.create(name, 'group'))
507
504
  end
508
505
 
509
506
  def self.exists?(name_or_sid)
510
507
  well_known = false
511
- if (sid = Puppet::Util::Windows::SID.name_to_sid_object(name_or_sid))
508
+ if (sid = Puppet::Util::Windows::SID.name_to_principal(name_or_sid))
512
509
  return true if sid.account_type == :SidTypeGroup
513
510
 
514
511
  # 'well known group' is special as it can be a group like Everyone OR a user like SYSTEM
@@ -111,11 +111,15 @@ module Puppet::Util::Windows::File
111
111
 
112
112
  # return true if path exists and it's not a symlink
113
113
  # Other file attributes are ignored. https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx
114
- return true if (result & FILE_ATTRIBUTE_REPARSE_POINT) != FILE_ATTRIBUTE_REPARSE_POINT
115
-
116
- # walk the symlink and try again...
117
- seen_paths << path.downcase
118
- path = readlink(path)
114
+ reparse_point = (result & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
115
+ if reparse_point && symlink_reparse_point?(path)
116
+ # walk the symlink and try again...
117
+ seen_paths << path.downcase
118
+ path = readlink(path)
119
+ else
120
+ # file was found and its not a symlink
121
+ return true
122
+ end
119
123
  end
120
124
 
121
125
  false
@@ -177,6 +181,18 @@ module Puppet::Util::Windows::File
177
181
  "#{flags_and_attributes.to_s(8)}, #{template_file_handle})")
178
182
  end
179
183
 
184
+ IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
185
+ IO_REPARSE_TAG_HSM = 0xC0000004
186
+ IO_REPARSE_TAG_HSM2 = 0x80000006
187
+ IO_REPARSE_TAG_SIS = 0x80000007
188
+ IO_REPARSE_TAG_WIM = 0x80000008
189
+ IO_REPARSE_TAG_CSV = 0x80000009
190
+ IO_REPARSE_TAG_DFS = 0x8000000A
191
+ IO_REPARSE_TAG_SYMLINK = 0xA000000C
192
+ IO_REPARSE_TAG_DFSR = 0x80000012
193
+ IO_REPARSE_TAG_DEDUP = 0x80000013
194
+ IO_REPARSE_TAG_NFS = 0x80000014
195
+
180
196
  def self.get_reparse_point_data(handle, &block)
181
197
  # must be multiple of 1024, min 10240
182
198
  FFI::MemoryPointer.new(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) do |reparse_data_buffer_ptr|
@@ -184,11 +200,11 @@ module Puppet::Util::Windows::File
184
200
 
185
201
  reparse_tag = reparse_data_buffer_ptr.read_win32_ulong
186
202
  buffer_type = case reparse_tag
187
- when 0xA000000C
203
+ when IO_REPARSE_TAG_SYMLINK
188
204
  SYMLINK_REPARSE_DATA_BUFFER
189
- when 0xA0000003
205
+ when IO_REPARSE_TAG_MOUNT_POINT
190
206
  MOUNT_POINT_REPARSE_DATA_BUFFER
191
- when 0x80000014
207
+ when IO_REPARSE_TAG_NFS
192
208
  raise Puppet::Util::Windows::Error.new("Retrieving NFS reparse point data is unsupported")
193
209
  else
194
210
  raise Puppet::Util::Windows::Error.new("DeviceIoControl(#{handle}, " +
@@ -202,6 +218,20 @@ module Puppet::Util::Windows::File
202
218
  nil
203
219
  end
204
220
 
221
+ def self.get_reparse_point_tag(handle)
222
+ reparse_tag = nil
223
+
224
+ # must be multiple of 1024, min 10240
225
+ FFI::MemoryPointer.new(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) do |reparse_data_buffer_ptr|
226
+ device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, reparse_data_buffer_ptr)
227
+
228
+ # DWORD ReparseTag is the first member of the struct
229
+ reparse_tag = reparse_data_buffer_ptr.read_win32_ulong
230
+ end
231
+
232
+ reparse_tag
233
+ end
234
+
205
235
  def self.device_io_control(handle, io_control_code, in_buffer = nil, out_buffer = nil)
206
236
  if out_buffer.nil?
207
237
  raise Puppet::Util::Windows::Error.new("out_buffer is required")
@@ -229,12 +259,18 @@ module Puppet::Util::Windows::File
229
259
  end
230
260
 
231
261
  FILE_ATTRIBUTE_REPARSE_POINT = 0x400
232
- def symlink?(file_name)
262
+ def reparse_point?(file_name)
233
263
  attributes = get_attributes(file_name, false)
234
264
 
235
265
  return false if (attributes == INVALID_FILE_ATTRIBUTES)
236
266
  (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
237
267
  end
268
+ module_function :reparse_point?
269
+
270
+ def symlink?(file_name)
271
+ # Puppet currently only handles mount point and symlink reparse points, ignores others
272
+ reparse_point?(file_name) && symlink_reparse_point?(file_name)
273
+ end
238
274
  module_function :symlink?
239
275
 
240
276
  GENERIC_READ = 0x80000000
@@ -375,6 +411,22 @@ module Puppet::Util::Windows::File
375
411
  path
376
412
  end
377
413
 
414
+ # these reparse point types are the only ones Puppet currently understands
415
+ # so rather than raising an exception in readlink, prefer to not consider
416
+ # the path a symlink when stat'ing later
417
+ def self.symlink_reparse_point?(path)
418
+ symlink = false
419
+
420
+ open_symlink(path) do |handle|
421
+ symlink = [
422
+ IO_REPARSE_TAG_SYMLINK,
423
+ IO_REPARSE_TAG_MOUNT_POINT
424
+ ].include?(get_reparse_point_tag(handle))
425
+ end
426
+
427
+ symlink
428
+ end
429
+
378
430
  ffi_convention :stdcall
379
431
 
380
432
  # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365512(v=vs.85).aspx