puppet 5.3.5 → 5.3.6

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 (71) hide show
  1. data/lib/puppet/application/cert.rb +3 -1
  2. data/lib/puppet/application/device.rb +99 -12
  3. data/lib/puppet/application/lookup.rb +11 -1
  4. data/lib/puppet/context.rb +1 -1
  5. data/lib/puppet/functions/map.rb +1 -1
  6. data/lib/puppet/indirector/request.rb +6 -10
  7. data/lib/puppet/indirector/rest.rb +9 -9
  8. data/lib/puppet/network/http/connection.rb +8 -0
  9. data/lib/puppet/parser/compiler.rb +7 -0
  10. data/lib/puppet/parser/functions/new.rb +31 -46
  11. data/lib/puppet/parser/functions/return.rb +22 -1
  12. data/lib/puppet/provider/group/windows_adsi.rb +4 -7
  13. data/lib/puppet/provider/service/systemd.rb +1 -1
  14. data/lib/puppet/provider/user/aix.rb +1 -1
  15. data/lib/puppet/provider/user/windows_adsi.rb +1 -1
  16. data/lib/puppet/reference/configuration.rb +2 -0
  17. data/lib/puppet/resource/catalog.rb +1 -1
  18. data/lib/puppet/type/user.rb +34 -3
  19. data/lib/puppet/util/plist.rb +1 -1
  20. data/lib/puppet/util/reference.rb +1 -8
  21. data/lib/puppet/util/windows/adsi.rb +15 -18
  22. data/lib/puppet/util/windows/principal.rb +7 -6
  23. data/lib/puppet/util/windows/sid.rb +60 -7
  24. data/lib/puppet/version.rb +1 -1
  25. data/locales/ja/puppet.po +163 -140
  26. data/locales/puppet.pot +94 -76
  27. data/man/man5/puppet.conf.5 +91 -16
  28. data/man/man8/puppet-agent.8 +6 -2
  29. data/man/man8/puppet-apply.8 +2 -2
  30. data/man/man8/puppet-ca.8 +1 -1
  31. data/man/man8/puppet-catalog.8 +1 -1
  32. data/man/man8/puppet-cert.8 +1 -1
  33. data/man/man8/puppet-certificate.8 +1 -1
  34. data/man/man8/puppet-certificate_request.8 +1 -1
  35. data/man/man8/puppet-certificate_revocation_list.8 +1 -1
  36. data/man/man8/puppet-config.8 +1 -1
  37. data/man/man8/puppet-describe.8 +1 -1
  38. data/man/man8/puppet-device.8 +33 -11
  39. data/man/man8/puppet-doc.8 +1 -1
  40. data/man/man8/puppet-epp.8 +1 -1
  41. data/man/man8/puppet-facts.8 +1 -1
  42. data/man/man8/puppet-filebucket.8 +22 -4
  43. data/man/man8/puppet-generate.8 +1 -1
  44. data/man/man8/puppet-help.8 +1 -1
  45. data/man/man8/puppet-key.8 +1 -1
  46. data/man/man8/puppet-lookup.8 +1 -1
  47. data/man/man8/puppet-man.8 +1 -1
  48. data/man/man8/puppet-master.8 +1 -1
  49. data/man/man8/puppet-module.8 +11 -2
  50. data/man/man8/puppet-node.8 +1 -1
  51. data/man/man8/puppet-parser.8 +1 -1
  52. data/man/man8/puppet-plugin.8 +1 -1
  53. data/man/man8/puppet-report.8 +1 -1
  54. data/man/man8/puppet-resource.8 +1 -1
  55. data/man/man8/puppet-status.8 +1 -1
  56. data/man/man8/puppet.8 +2 -2
  57. data/spec/integration/application/lookup_spec.rb +21 -0
  58. data/spec/integration/util/windows/adsi_spec.rb +86 -1
  59. data/spec/integration/util/windows/principal_spec.rb +10 -1
  60. data/spec/unit/application/cert_spec.rb +17 -5
  61. data/spec/unit/application/device_spec.rb +96 -2
  62. data/spec/unit/indirector/rest_spec.rb +43 -0
  63. data/spec/unit/parser/compiler_spec.rb +8 -0
  64. data/spec/unit/provider/group/windows_adsi_spec.rb +79 -22
  65. data/spec/unit/provider/service/systemd_spec.rb +1 -1
  66. data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
  67. data/spec/unit/util/plist_spec.rb +3 -3
  68. data/spec/unit/util/windows/adsi_spec.rb +31 -27
  69. data/spec/unit/util/windows/sid_spec.rb +86 -15
  70. data/tasks/manpages.rake +1 -1
  71. metadata +3415 -3415
@@ -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
@@ -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
@@ -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","18.04"]
29
29
  defaultfor :operatingsystem => :cumuluslinux, :operatingsystemmajrelease => ["3"]
30
30
 
31
31
  def self.instances
@@ -275,7 +275,7 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do
275
275
  # Must receive "user:enc_password" as input
276
276
  # command, arguments = {:failonfail => true, :combine => true}
277
277
  # Fix for bugs #11200 and #10915
278
- cmd = [self.class.command(:chpasswd), get_ia_module_args, '-e', '-c', user].flatten
278
+ cmd = [self.class.command(:chpasswd), get_ia_module_args, '-e', '-c'].flatten
279
279
  begin
280
280
  output = execute(cmd, {:failonfail => false, :combine => true, :stdinfile => tmpfile.path })
281
281
  # 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.
@@ -595,7 +595,7 @@ class Puppet::Resource::Catalog < Puppet::Graph::SimpleGraph
595
595
  transaction = Puppet::Transaction.new(self, options[:report], prioritizer)
596
596
  transaction.tags = options[:tags] if options[:tags]
597
597
  transaction.ignoreschedules = true if options[:ignoreschedules]
598
- transaction.for_network_device = options[:network_device]
598
+ transaction.for_network_device = Puppet.lookup(:network_device) { nil } || options[:network_device]
599
599
 
600
600
  transaction
601
601
  end
@@ -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?(":")
@@ -41,7 +41,7 @@ module Puppet::Util::Plist
41
41
 
42
42
  Puppet.debug "Plist #{file_path} ill-formatted, converting with plutil"
43
43
  begin
44
- plist = Puppet::Util::Execution.execute(['/usr/bin/plutil', '-convert', 'xml1', '-o', '/dev/stdout', file_path],
44
+ plist = Puppet::Util::Execution.execute(['/usr/bin/plutil', '-convert', 'xml1', '-o', '-', file_path],
45
45
  {:failonfail => true, :combine => true})
46
46
  return parse_plist(plist)
47
47
  rescue Puppet::ExecutionFailure => detail
@@ -12,10 +12,6 @@ class Puppet::Util::Reference
12
12
 
13
13
  instance_load(:reference, 'puppet/reference')
14
14
 
15
- def self.footer
16
- "\n\n----------------\n\n" + _("*This page autogenerated on %{current_time}*\n") % { current_time: Time.now.to_s }
17
- end
18
-
19
15
  def self.modes
20
16
  %w{pdf text}
21
17
  end
@@ -111,15 +107,12 @@ class Puppet::Util::Reference
111
107
  def to_markdown(withcontents = true)
112
108
  # First the header
113
109
  text = markdown_header(@title, 1)
114
- #TRANSLATORS message accompanied by date of generation
115
- text << _("\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on %{current_time})*\n\n") % { current_time: Time.now.to_s }
110
+ text << _("\n\n**This page is autogenerated; any changes will get overwritten**\n\n")
116
111
 
117
112
  text << @header
118
113
 
119
114
  text << generate
120
115
 
121
- text << self.class.footer if withcontents
122
-
123
116
  text
124
117
  end
125
118
  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
@@ -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
 
@@ -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,7 +154,7 @@ 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)
157
+ sid = Puppet::Util::Windows::SID.name_to_principal(name)
156
158
  raise Puppet::Error.new( _("Could not resolve name: %{name}") % { name: name } ) if !sid
157
159
  [sid.sid, sid]
158
160
  end
@@ -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
@@ -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
@@ -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
@@ -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?
@@ -508,7 +505,7 @@ module Puppet::Util::Windows::ADSI
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
@@ -32,9 +32,10 @@ module Puppet::Util::Windows::SID
32
32
  @sid_bytes == compare.sid_bytes
33
33
  end
34
34
 
35
- # added for backward compatibility
35
+ # returns authority qualified account name
36
+ # prefer to compare Principal instances with == operator or by #sid
36
37
  def to_s
37
- @sid
38
+ @domain_account
38
39
  end
39
40
 
40
41
  # = 8 + max sub identifiers (15) * 4
@@ -64,14 +65,14 @@ module Puppet::Util::Windows::SID
64
65
  last_error = FFI.errno
65
66
 
66
67
  if (success == FFI::WIN32_FALSE && last_error != ERROR_INSUFFICIENT_BUFFER)
67
- raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountNameW'), last_error)
68
+ raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountNameW with account: %{account_name}') % { account_name: account_name}, last_error)
68
69
  end
69
70
 
70
71
  FFI::MemoryPointer.new(:lpwstr, domain_length_ptr.read_dword) do |domain_ptr|
71
72
  if LookupAccountNameW(system_name_ptr, account_name_ptr,
72
73
  sid_ptr, sid_length_ptr,
73
74
  domain_ptr, domain_length_ptr, name_use_enum_ptr) == FFI::WIN32_FALSE
74
- raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountNameW'))
75
+ raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountNameW with account: %{account_name}') % { account_name: account_name} )
75
76
  end
76
77
 
77
78
  # with a SID returned, loop back through lookup_account_sid to retrieve official name
@@ -116,14 +117,14 @@ module Puppet::Util::Windows::SID
116
117
  last_error = FFI.errno
117
118
 
118
119
  if (success == FFI::WIN32_FALSE && last_error != ERROR_INSUFFICIENT_BUFFER)
119
- raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountSidW'), last_error)
120
+ raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountSidW with bytes: %{sid_bytes}') % { sid_bytes: sid_bytes}, last_error)
120
121
  end
121
122
 
122
123
  FFI::MemoryPointer.new(:lpwstr, name_length_ptr.read_dword) do |name_ptr|
123
124
  FFI::MemoryPointer.new(:lpwstr, domain_length_ptr.read_dword) do |domain_ptr|
124
125
  if LookupAccountSidW(system_name_ptr, sid_ptr, name_ptr, name_length_ptr,
125
126
  domain_ptr, domain_length_ptr, name_use_enum_ptr) == FFI::WIN32_FALSE
126
- raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountSidW'))
127
+ raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountSidW with bytes: %{sid_bytes}') % { sid_bytes: sid_bytes} )
127
128
  end
128
129
 
129
130
  return new(
@@ -52,18 +52,18 @@ module Puppet::Util::Windows
52
52
  # 'BUILTIN\Administrators', or 'S-1-5-32-544', and will return the
53
53
  # SID. Returns nil if the account doesn't exist.
54
54
  def name_to_sid(name)
55
- sid = name_to_sid_object(name)
55
+ sid = name_to_principal(name)
56
56
 
57
57
  sid ? sid.sid : nil
58
58
  end
59
59
  module_function :name_to_sid
60
60
 
61
- # Convert an account name, e.g. 'Administrators' into a SID object,
61
+ # Convert an account name, e.g. 'Administrators' into a Principal::SID object,
62
62
  # e.g. 'S-1-5-32-544'. The name can be specified as 'Administrators',
63
63
  # 'BUILTIN\Administrators', or 'S-1-5-32-544', and will return the
64
64
  # SID object. Returns nil if the account doesn't exist.
65
65
  # This method returns a SID::Principal with the account, domain, SID, etc
66
- def name_to_sid_object(name)
66
+ def name_to_principal(name)
67
67
  # Apparently, we accept a symbol..
68
68
  name = name.to_s.strip if name
69
69
 
@@ -81,21 +81,50 @@ module Puppet::Util::Windows
81
81
  rescue
82
82
  nil
83
83
  end
84
- module_function :name_to_sid_object
84
+ module_function :name_to_principal
85
+ class << self; alias name_to_sid_object name_to_principal; end
85
86
 
86
- # Converts an octet string array of bytes to a SID object,
87
+ # Converts an octet string array of bytes to a SID::Principal object,
87
88
  # e.g. [1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0] is the representation for
88
89
  # S-1-5-18, the local 'SYSTEM' account.
89
90
  # Raises an Error for nil or non-array input.
90
91
  # This method returns a SID::Principal with the account, domain, SID, etc
91
- def octet_string_to_sid_object(bytes)
92
+ def octet_string_to_principal(bytes)
92
93
  if !bytes || !bytes.respond_to?('pack') || bytes.empty?
93
94
  raise Puppet::Util::Windows::Error.new(_("Octet string must be an array of bytes"))
94
95
  end
95
96
 
96
97
  Principal.lookup_account_sid(bytes)
97
98
  end
98
- module_function :octet_string_to_sid_object
99
+ module_function :octet_string_to_principal
100
+ class << self; alias octet_string_to_sid_object octet_string_to_principal; end
101
+
102
+ # Converts a COM instance of IAdsUser or IAdsGroup to a SID::Principal object,
103
+ # Raises an Error for nil or an object without an objectSID / Name property.
104
+ # This method returns a SID::Principal with the account, domain, SID, etc
105
+ # This method will return instances even when the SID is unresolvable, as
106
+ # may be the case when domain users have been added to local groups, but
107
+ # removed from the domain
108
+ def ads_to_principal(ads_object)
109
+ if !ads_object || !ads_object.respond_to?(:ole_respond_to?) ||
110
+ !ads_object.ole_respond_to?(:objectSID) || !ads_object.ole_respond_to?(:Name)
111
+ raise Puppet::Error.new("ads_object must be an IAdsUser or IAdsGroup instance")
112
+ end
113
+ octet_string_to_principal(ads_object.objectSID)
114
+ rescue Puppet::Util::Windows::Error => e
115
+ # if the error is not a lookup / mapping problem, immediately re-raise
116
+ raise if e.code != ERROR_NONE_MAPPED
117
+
118
+ # if the Name property isn't formatted like a SID, OR
119
+ if !valid_sid?(ads_object.Name) ||
120
+ # if the objectSID doesn't match the Name property, also raise
121
+ ((converted = octet_string_to_sid_string(ads_object.objectSID)) != ads_object.Name)
122
+ raise Puppet::Error.new("ads_object Name: #{ads_object.Name} invalid or does not match objectSID: #{ads_object.objectSID} (#{converted})", e)
123
+ end
124
+
125
+ unresolved_principal(ads_object.Name, ads_object.objectSID)
126
+ end
127
+ module_function :ads_to_principal
99
128
 
100
129
  # Convert a SID string, e.g. "S-1-5-32-544" to a name,
101
130
  # e.g. 'BUILTIN\Administrators'. Returns nil if an account
@@ -193,6 +222,30 @@ module Puppet::Util::Windows
193
222
  end
194
223
  module_function :get_length_sid
195
224
 
225
+ def octet_string_to_sid_string(sid_bytes)
226
+ sid_string = nil
227
+
228
+ FFI::MemoryPointer.new(:byte, sid_bytes.length) do |sid_ptr|
229
+ sid_ptr.write_array_of_uchar(sid_bytes)
230
+ sid_string = Puppet::Util::Windows::SID.sid_ptr_to_string(sid_ptr)
231
+ end
232
+
233
+ sid_string
234
+ end
235
+ module_function :octet_string_to_sid_string
236
+
237
+ # @api private
238
+ def self.unresolved_principal(name, sid_bytes)
239
+ Principal.new(
240
+ name + " (unresolvable)", # account
241
+ sid_bytes, # sid_bytes
242
+ name, # sid string
243
+ nil, #domain
244
+ # https://msdn.microsoft.com/en-us/library/cc245534.aspx?f=255&MSPPError=-2147217396
245
+ # Indicates that the type of object could not be determined. For example, no object with that SID exists.
246
+ :SidTypeUnknown)
247
+ end
248
+
196
249
  ffi_convention :stdcall
197
250
 
198
251
  # https://msdn.microsoft.com/en-us/library/windows/desktop/aa379151(v=vs.85).aspx