Module: Puppet::Provider::Acl::Windows::Base

Defined in:
lib/puppet/provider/acl/windows/base.rb

Overview

Provides the detailed implementation details for the provider and should shield the provider from legacy support implementations that would happen here.

For information on ACE masks see: Win32_ACE Class, Standard Access Rights, Generic Access Rights

Constant Summary collapse

REFRESH_SD =

Used to specify to flush out the SD cache.

true
DO_NOT_REFRESH_SD =

Used to specify to flush out the SD cache.

false
GENERIC_ALL =

Grants all possible access rights.

0x10000000
GENERIC_WRITE =

Grants write access.

0x40000000
GENERIC_READ =

Grants read access.

0x80000000
GENERIC_EXECUTE =

Grants execute access.

0x20000000
DELETE =

Grants delete access.

0x00010000
SYNCHRONIZE =

Synchronizes access and allows a process to wait for an object to enter the signaled state.

0x100000
STANDARD_RIGHTS_REQUIRED =

Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access.

0xf0000
STANDARD_RIGHTS_READ =

Currently defined to equal READ_CONTROL.

0x20000
STANDARD_RIGHTS_WRITE =

Currently defined to equal READ_CONTROL.

0x20000
STANDARD_RIGHTS_EXECUTE =

Currently defined to equal READ_CONTROL.

0x20000
FILE_READ_DATA =

Grants the right to read data from the file. For a directory, this value grants the right to list the contents of the directory.

1
FILE_WRITE_DATA =

Grants the right to write data to the file. For a directory, this value grants the right to create a file in the directory.

2
FILE_APPEND_DATA =

Grants the right to append data to the file. For a directory, this value grants the right to create a subdirectory.

4
FILE_READ_EA =

Grants the right to read extended attributes.

8
FILE_WRITE_EA =

Grants the right to write extended attributes.

16
FILE_EXECUTE =

Grants the right to execute a file. For a directory, the directory can be traversed.

32
FILE_DELETE_CHILD =

Grants the right to delete a directory and all the files it contains (its children), even if the files are read-only.

64
FILE_READ_ATTRIBUTES =

Grants the right to read file attributes.

128
FILE_WRITE_ATTRIBUTES =

Grants the right to change file attributes.

256
FILE_ALL_ACCESS =

Grants full read, write and execute permissions.

STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF
FILE_GENERIC_READ =

A combination of masks providing a generic mask for reading files along with associated file and extended attributes.

STANDARD_RIGHTS_READ |
FILE_READ_DATA |
FILE_READ_ATTRIBUTES |
FILE_READ_EA |
SYNCHRONIZE
FILE_GENERIC_WRITE =

A combination of masks providing a generic mask for writing files along with associated file and extended attributes.

STANDARD_RIGHTS_WRITE |
FILE_WRITE_DATA |
FILE_WRITE_ATTRIBUTES |
FILE_WRITE_EA |
FILE_APPEND_DATA |
SYNCHRONIZE
FILE_GENERIC_EXECUTE =

A combination of masks providing a generic mask for executing files.

STANDARD_RIGHTS_EXECUTE |
FILE_READ_ATTRIBUTES |
FILE_EXECUTE |
SYNCHRONIZE

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.get_account_flags(permission) ⇒ Array

Retrieve the propagation rule flags from a specified ACE.

Parameters:

  • permission (Puppet::Util::Windows::AccessControlEntry)

Returns:

  • (Array)

    Flags associated with ACE.



407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/puppet/provider/acl/windows/base.rb', line 407

def (permission)
  # http://msdn.microsoft.com/en-us/library/ms229747.aspx
  flags = 0x0

  case permission.child_types
  when :all
    flags = flags |
            Puppet::Util::Windows::AccessControlEntry::OBJECT_INHERIT_ACE |
            Puppet::Util::Windows::AccessControlEntry::CONTAINER_INHERIT_ACE
  when :objects
    flags |= Puppet::Util::Windows::AccessControlEntry::OBJECT_INHERIT_ACE
  when :containers
    flags |= Puppet::Util::Windows::AccessControlEntry::CONTAINER_INHERIT_ACE
  end

  case permission.affects
  when :self_only
    flags = 0x0
  when :children_only
    flags |= Puppet::Util::Windows::AccessControlEntry::INHERIT_ONLY_ACE
  when :self_and_direct_children_only
    flags |= Puppet::Util::Windows::AccessControlEntry::NO_PROPAGATE_INHERIT_ACE
  when :direct_children_only
    flags = flags |
            Puppet::Util::Windows::AccessControlEntry::NO_PROPAGATE_INHERIT_ACE |
            Puppet::Util::Windows::AccessControlEntry::INHERIT_ONLY_ACE
  end

  if permission.child_types == :none && flags != 0x0
    flags = 0x0
  end

  flags
end

.get_account_mask(permission, target_resource_type = :file) ⇒ Integer

Retrieves mask from a supplied ACE

Parameters:

  • permission (Puppet::Util::Windows::AccessControlEntry)
  • target_resource_type (Symbol) (defaults to: :file)

Returns:

  • (Integer)

    Extracted account mask



364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/puppet/provider/acl/windows/base.rb', line 364

def (permission, target_resource_type = :file)
  return 0 if permission.nil?
  return permission.mask.to_i if permission.mask
  return 0 if permission.rights.nil? || permission.rights.empty?

  mask = case target_resource_type
         when :file
           begin
             if permission.rights.include?(:full)
               return FILE_ALL_ACCESS
             end

             if permission.rights.include?(:modify)
               return DELETE |
                      FILE_GENERIC_WRITE |
                      FILE_GENERIC_READ  |
                      FILE_GENERIC_EXECUTE
             end

             filemask = 0x0
             if permission.rights.include?(:write)
               filemask |= FILE_GENERIC_WRITE
             end

             if permission.rights.include?(:read)
               filemask |= FILE_GENERIC_READ
             end

             if permission.rights.include?(:execute)
               filemask |= FILE_GENERIC_EXECUTE
             end

             filemask
           end
         end
  mask
end

.get_ace_child_types(ace) ⇒ Symbol

Returns child types of supplied ACE.

Parameters:

  • ace (Puppet::Util::Windows::AccessControlEntry)

Returns:

  • (Symbol)

    Child types of supplied ACE.



266
267
268
269
270
271
272
273
274
275
276
# File 'lib/puppet/provider/acl/windows/base.rb', line 266

def get_ace_child_types(ace)
  return :all if ace.nil?

  # the order is on purpose
  child_types = :none
  child_types = :objects if ace.object_inherit?
  child_types = :containers if ace.container_inherit?
  child_types = :all if ace.object_inherit? && ace.container_inherit?

  child_types
end

.get_ace_propagation(ace) ⇒ Symbol

Retrieves propagation of supplied ACE.

Parameters:

  • ace (Puppet::Util::Windows::AccessControlEntry)

Returns:

  • (Symbol)

    Propagation rule of supplied ACE.



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/puppet/provider/acl/windows/base.rb', line 283

def get_ace_propagation(ace)
  # http://msdn.microsoft.com/en-us/library/ms229747.aspx
  return :all if ace.nil?

  targets_self = true unless ace.inherit_only?
  targets_children = true if ace.object_inherit? || ace.container_inherit?
  targets_children_only = true if ace.inherit_only?

  # the order is on purpose
  affects = :self_only if targets_self
  affects = :children_only if targets_children_only
  affects = :all if targets_self && targets_children

  # Puppet::Util::Windows::AccessControlEntry defines the propagation flag but doesn't provide a method
  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms692524(v=vs.85).aspx
  no_propagate_flag = 0x4
  propagate = ace.flags & no_propagate_flag != no_propagate_flag
  unless propagate
    affects = :self_and_direct_children_only if targets_self && targets_children
    affects = :direct_children_only if targets_children_only
  end

  affects
end

.get_ace_rights_from_mask(ace) ⇒ Array

Retrieves the access rights from an ACE’s access mask.

Parameters:

  • ace (Ace)

Returns:

  • (Array)

    Collection of symbols corresponding to AccessRights



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/puppet/provider/acl/windows/base.rb', line 183

def get_ace_rights_from_mask(ace)
  # TODO: v2 check that this is a file type and respond appropriately
  rights = []
  return rights if ace.nil?
  mask_specific_remainder = ace.mask

  # full
  if (ace.mask & GENERIC_ALL) == GENERIC_ALL ||
     (ace.mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS
    rights << :full
    mask_specific_remainder = 0
  end

  if rights == []
    if (ace.mask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE
      rights << :write
      mask_specific_remainder &= ~FILE_GENERIC_WRITE
    end
    if (ace.mask & GENERIC_WRITE) == GENERIC_WRITE
      rights << :write
      mask_specific_remainder &= ~GENERIC_WRITE
    end

    if (ace.mask & FILE_GENERIC_READ) == FILE_GENERIC_READ
      rights << :read
      mask_specific_remainder &= ~FILE_GENERIC_READ
    end
    if (ace.mask & GENERIC_READ) == GENERIC_READ
      rights << :read
      mask_specific_remainder &= ~GENERIC_READ
    end

    if (ace.mask & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE
      rights << :execute
      mask_specific_remainder &= ~FILE_GENERIC_EXECUTE
    end
    if (ace.mask & GENERIC_EXECUTE) == GENERIC_EXECUTE
      rights << :execute
      mask_specific_remainder &= ~GENERIC_EXECUTE
    end
  end

  # modify
  # if the rights appending changes above, we'll
  # need to ensure this check is still good
  if rights == [:write, :read, :execute] &&
     (ace.mask & DELETE) == DELETE
    rights = [:modify]
    mask_specific_remainder &= ~DELETE
  end

  # rights are too specific, use mask
  if rights == []
    rights << :mask_specific
  elsif mask_specific_remainder != 0
    Puppet.debug("Remainder from #{ace.mask} is #{mask_specific_remainder}")
    rights = [:mask_specific]
  end

  rights
end

.get_ace_type(ace) ⇒ Symbol

Retrieves the type of a supplied ACE.

Parameters:

  • ace (Puppet::Util::Windows::AccessControlEntry)

Returns:

  • (Symbol)

    Type of supplied ACE



250
251
252
253
254
255
256
257
258
259
# File 'lib/puppet/provider/acl/windows/base.rb', line 250

def get_ace_type(ace)
  return :allow if ace.nil?

  ace_type = case ace.type
             when Puppet::Util::Windows::AccessControlEntry::ACCESS_ALLOWED_ACE_TYPE then :allow
             when Puppet::Util::Windows::AccessControlEntry::ACCESS_DENIED_ACE_TYPE then :deny
             end

  ace_type
end

Instance Method Details

#account_insync?(current, should) ⇒ Bool

Compares two SIDs to determine if they contain the same account id.

Parameters:

  • current (Puppet::Util::Windows::SID)
  • should (Puppet::Util::Windows::SID)

Returns:

  • (Bool)

    True if ‘current` account id is `should` account id.



513
514
515
516
517
518
519
520
# File 'lib/puppet/provider/acl/windows/base.rb', line 513

def (current, should)
  return false unless current

  should_empty = should.nil? || should.empty?
  return false if current.empty? != should_empty

  (current) == (should)
end

#are_permissions_insync?(current_permissions, specified_permissions, purge_value = :false) ⇒ Boolean

TODO

Returns:

  • (Boolean)


310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/puppet/provider/acl/windows/base.rb', line 310

def are_permissions_insync?(current_permissions, specified_permissions, purge_value = :false)
  return false if current_permissions.nil? && !specified_permissions.nil? && purge_value != :listed_permissions

  purge_value = purge_value.to_s.downcase.to_sym unless purge_value.is_a?(Symbol)
  should_purge = purge_value == :true
  remove_permissions = purge_value == :listed_permissions
  current_local_permissions = if current_permissions.nil?
                                []
                              else
                                current_permissions.reject { |p| p.inherited? }
                              end

  if should_purge
    current_local_permissions == specified_permissions
  elsif remove_permissions
    return true if specified_permissions.nil?
    (specified_permissions & current_local_permissions) == []
  else
    return true if specified_permissions.nil?

    # intersect will return order by left item in intersect
    #  order is guaranteed checked when specified_permissions
    (current_local_permissions & specified_permissions) == specified_permissions
  end
end

#convert_to_dacl(permissions) ⇒ Puppet::Util::Windows::AccessControlList

Converts an array of permissions into a DACL object.

Parameters:

  • permissions (Array)

    Array of ACEs.

Returns:

  • (Puppet::Util::Windows::AccessControlList)

    ACL of supplied ACEs.



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/puppet/provider/acl/windows/base.rb', line 340

def convert_to_dacl(permissions)
  dacl = Puppet::Util::Windows::AccessControlList.new
  return dacl if permissions.nil? || permissions.empty?

  permissions.each do |permission|
    sid = (permission.identity)
    mask = (permission)
    flags = (permission)
    case permission.perm_type
    when :allow
      dacl.allow(sid, mask, flags)
    when :deny
      dacl.deny(sid, mask, flags)
    end
  end

  dacl
end

#convert_to_permissions_hash(ace) ⇒ Hash

Converts an Ace object into a hash.

Parameters:

  • ace (Puppet::Util::Windows::AccessControlEntry)

Returns:

  • (Hash)

    Supplied ACE in the form of a hash.



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/puppet/provider/acl/windows/base.rb', line 161

def convert_to_permissions_hash(ace)
  return {} if ace.nil?

  sid = ace.sid
  identity = sid_to_name(sid)
  rights = get_ace_rights_from_mask(ace)
  ace_type = get_ace_type(ace)
  child_types = get_ace_child_types(ace)
  affects = get_ace_propagation(ace)
  is_inherited = ace.inherited?
  hash = { 'identity' => identity.to_s, 'id' => sid.to_s, 'rights' => rights,
           'perm_type' => ace_type, 'child_types' => child_types,
           'affects' => affects, 'is_inherited' => is_inherited,
           'mask' => ace.mask.to_s }

  hash
end

#get_account_id(name) ⇒ Puppet::Util::Windows::SID

Converts an account name into an SID.

Parameters:

  • name (String)

Returns:

  • (Puppet::Util::Windows::SID)

    Converted SID.



526
527
528
529
530
531
532
533
534
535
536
# File 'lib/puppet/provider/acl/windows/base.rb', line 526

def (name)
  # sometimes the name will come in with a SID
  # which will return nil when we call name_to_sid
  # if the user no longer exists
  return unless name
  if valid_sid?(name)
    name
  else
    name_to_sid(name)
  end
end

#get_account_name(current_value) ⇒ String Also known as: get_group_name

Retrieves name from SID

Parameters:

  • current_value (Puppet::Util::Windows::SID)

Returns:

  • (String)

    If ‘current_value` contains name returns this else return `current_value`.



542
543
544
545
546
# File 'lib/puppet/provider/acl/windows/base.rb', line 542

def (current_value)
  name = sid_to_name((current_value))

  name ? name : current_value
end

#get_current_groupString

Retrieves group from current instance’s SecurityDescriptor.

Returns:

  • (String)

    SID group.



502
503
504
505
506
# File 'lib/puppet/provider/acl/windows/base.rb', line 502

def get_current_group
  sd = get_security_descriptor

  sd&.group
end

#get_current_ownerString

Retrieves owner from current instance’s SecurityDescriptor.

Returns:

  • (String)

    SID owner.



493
494
495
496
497
# File 'lib/puppet/provider/acl/windows/base.rb', line 493

def get_current_owner
  sd = get_security_descriptor

  sd&.owner
end

#get_current_permissionsArray

Retrieves permissions of current instance.

Returns:

  • (Array)

    ACEs of current instance.



145
146
147
148
149
150
151
152
153
154
155
# File 'lib/puppet/provider/acl/windows/base.rb', line 145

def get_current_permissions
  sd = get_security_descriptor(DO_NOT_REFRESH_SD)
  permissions = []
  unless sd.nil?
    permissions if sd.dacl.nil?
    sd.dacl.each do |ace|
      permissions << Puppet::Type::Acl::Ace.new(convert_to_permissions_hash(ace), self)
    end
  end
  permissions
end

#get_security_descriptor(refresh_sd = DO_NOT_REFRESH_SD) ⇒ Puppet::Util::Windows::SecurityDescriptor

Retrieves the SecurityDescriptor of the current instance

Parameters:

  • refresh_sd (Bool) (defaults to: DO_NOT_REFRESH_SD)

    Whether to refresh the current instance’s SecurityDescriptor.

Returns:

  • (Puppet::Util::Windows::SecurityDescriptor)

    Instance’s SecurityDescriptors.



562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
# File 'lib/puppet/provider/acl/windows/base.rb', line 562

def get_security_descriptor(refresh_sd = DO_NOT_REFRESH_SD)
  refresh_sd ||= false
  if @security_descriptor.nil? || refresh_sd
    sd = nil
    case @resource[:target_type]
    when :file
      begin
        sd = Puppet::Util::Windows::Security.get_security_descriptor(@resource[:target])
      rescue => detail
        raise Puppet::Error, "Failed to get security descriptor for path '#{@resource[:target]}': #{detail}", detail.backtrace
      end
    end

    @security_descriptor = sd
  end

  @security_descriptor
end

#inheriting_permissions?Boolean

Returns:

  • (Boolean)


549
550
551
552
553
554
555
556
# File 'lib/puppet/provider/acl/windows/base.rb', line 549

def inheriting_permissions?
  sd = get_security_descriptor

  return !sd.protect unless sd.nil?

  # default true
  true
end

#name_to_sid(name) ⇒ Puppet::Util::Windows::SID

Note:

Puppet 3.7 deprecated methods at old locations in favor of SID class

Converts an account name into an SID string

Parameters:

  • name (String)

    Name+SID string

Returns:

  • (Puppet::Util::Windows::SID)

    Converted SID



110
111
112
113
114
115
116
# File 'lib/puppet/provider/acl/windows/base.rb', line 110

def name_to_sid(name)
  if Puppet::Util::Windows::SID.respond_to?(:name_to_sid)
    Puppet::Util::Windows::SID.name_to_sid(name)
  else
    Puppet::Util::Windows::Security.name_to_sid(name)
  end
end

#set_security_descriptor(security_descriptor) ⇒ Puppet::Util::Windows::SecurityDescriptor

Sets the instance’s SecurityDescriptor

Parameters:

  • security_descriptor (Puppet::Util::Windows::SecurityDescriptor)

Returns:

  • (Puppet::Util::Windows::SecurityDescriptor)

    Returns set SecurityDescriptor



585
586
587
588
589
590
591
592
593
594
595
596
597
# File 'lib/puppet/provider/acl/windows/base.rb', line 585

def set_security_descriptor(security_descriptor)
  case @resource[:target_type]
  when :file
    begin
      Puppet::Util::Windows::Security.set_security_descriptor(@resource[:target], security_descriptor)
    rescue => detail
      raise Puppet::Error, "Failed to set security descriptor for path '#{@resource[:target]}': #{detail}", detail.backtrace
    end
  end

  # flush out the cached sd
  get_security_descriptor(REFRESH_SD)
end

#sid_to_name(value) ⇒ String

Converts an SID string to an account name.

Parameters:

  • value (String)

    SID string

Returns:

  • (String)

    Extracted name



122
123
124
125
126
127
128
# File 'lib/puppet/provider/acl/windows/base.rb', line 122

def sid_to_name(value)
  if Puppet::Util::Windows::SID.respond_to?(:sid_to_name)
    Puppet::Util::Windows::SID.sid_to_name(value)
  else
    Puppet::Util::Windows::Security.sid_to_name(value)
  end
end

#sync_aces(current_dacl, should_aces, should_purge = false, remove_permissions = false) ⇒ Array

Ensures that the supplied DACL matches the additional supplied parameters.

Parameters:

  • current_dacl (Puppet::Util::Windows::AccessControlList)
  • should_aces (Array)
  • should_purge (Boolean) (defaults to: false)
  • remove_permissions (Boolean) (defaults to: false)

Returns:

  • (Array)

    Matching ACEs.



450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
# File 'lib/puppet/provider/acl/windows/base.rb', line 450

def sync_aces(current_dacl, should_aces, should_purge = false, remove_permissions = false)
  if remove_permissions
    kept_aces = []
    current_dacl.each do |ace|
      next if ace.inherited?

      current_ace = Puppet::Type::Acl::Ace.new(convert_to_permissions_hash(ace), self)
      existing_aces = should_aces.select { |a| a.same?(current_ace) }
      next unless existing_aces.empty?

      kept_aces << current_ace
    end

    should_aces = kept_aces
  else
    return should_aces if should_purge

    current_dacl.each do |ace|
      # TODO: v2 should we warn if we have an existing inherited ace that matches?
      next if ace.inherited?

      current_ace = Puppet::Type::Acl::Ace.new(convert_to_permissions_hash(ace), self)
      existing_aces = should_aces.select { |a| a.same?(current_ace) }
      next unless existing_aces.empty?

      # munge in existing unmanaged aces
      case current_ace.perm_type
      when :deny
        last_allow_index = should_aces.index { |a| a.perm_type == :allow }
        should_aces.insert(last_allow_index, current_ace) if last_allow_index
        should_aces << current_ace unless last_allow_index
      when :allow
        should_aces << current_ace
      end
    end
  end

  should_aces
end

#valid_sid?(string_sid) ⇒ Bool

Checks if supplied SID string is valid

Parameters:

  • string_sid (String)

    SID string

Returns:

  • (Bool)

    Whether supplied string is a valid SID



134
135
136
137
138
139
140
# File 'lib/puppet/provider/acl/windows/base.rb', line 134

def valid_sid?(string_sid)
  if Puppet::Util::Windows::SID.respond_to?(:valid_sid?)
    Puppet::Util::Windows::SID.valid_sid?(string_sid)
  else
    Puppet::Util::Windows::Security.valid_sid?(string_sid)
  end
end