Class: Puppet::Util::Windows::ADSI::User Private

Inherits:
ADSIObject show all
Extended by:
FFI::Library
Defined in:
lib/puppet/util/windows.rb,
lib/puppet/util/windows/adsi.rb

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Constant Summary collapse

ADS_USERFLAGS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Declare all of the available user flags on the system. Note that ADS_UF is read as ADS_UserFlag

https://docs.microsoft.com/en-us/windows/desktop/api/iads/ne-iads-ads_user_flag

and

https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user--pro

for the flag values.

{
  ADS_UF_SCRIPT:                                 0x0001,
  ADS_UF_ACCOUNTDISABLE:                         0x0002,
  ADS_UF_HOMEDIR_REQUIRED:                       0x0008,
  ADS_UF_LOCKOUT:                                0x0010,
  ADS_UF_PASSWD_NOTREQD:                         0x0020,
  ADS_UF_PASSWD_CANT_CHANGE:                     0x0040,
  ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED:        0x0080,
  ADS_UF_TEMP_DUPLICATE_ACCOUNT:                 0x0100,
  ADS_UF_NORMAL_ACCOUNT:                         0x0200,
  ADS_UF_INTERDOMAIN_TRUST_ACCOUNT:              0x0800,
  ADS_UF_WORKSTATION_TRUST_ACCOUNT:              0x1000,
  ADS_UF_SERVER_TRUST_ACCOUNT:                   0x2000,
  ADS_UF_DONT_EXPIRE_PASSWD:                     0x10000,
  ADS_UF_MNS_LOGON_ACCOUNT:                      0x20000,
  ADS_UF_SMARTCARD_REQUIRED:                     0x40000,
  ADS_UF_TRUSTED_FOR_DELEGATION:                 0x80000,
  ADS_UF_NOT_DELEGATED:                          0x100000,
  ADS_UF_USE_DES_KEY_ONLY:                       0x200000,
  ADS_UF_DONT_REQUIRE_PREAUTH:                   0x400000,
  ADS_UF_PASSWORD_EXPIRED:                       0x800000,
  ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION: 0x1000000
}
MAX_USERNAME_LENGTH =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

UNLEN from lmcons.h - stackoverflow.com/a/2155176

256
NameUnknown =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

docs.microsoft.com/en-us/windows/win32/api/secext/ne-secext-extended_name_format

0
NameFullyQualifiedDN =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

1
NameSamCompatible =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

2
NameDisplay =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

3
NameUniqueId =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

6
NameCanonical =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

7
NameUserPrincipal =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

8
NameCanonicalEx =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

9
NameServicePrincipal =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

10
NameDnsDomain =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

12
NameGivenName =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

13
NameSurname =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

14

Instance Attribute Summary

Attributes inherited from ADSIObject

#name

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ADSIObject

#[], #[]=, #commit, delete, each, exists?, get_sids, #initialize, localized_domains, name_sid_hash, #native_object, #object_class, parse_name, #sid, uri, #uri

Constructor Details

This class inherits a constructor from Puppet::Util::Windows::ADSI::ADSIObject

Class Method Details

.create(name) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises:


311
312
313
314
315
# File 'lib/puppet/util/windows/adsi.rb', line 311

def create(name)
  # Windows error 1379: The specified local group already exists.
  raise Puppet::Error.new(_("Cannot create user if group '%{name}' exists.") % { name: name }) if Puppet::Util::Windows::ADSI::Group.exists? name
  new(name, Puppet::Util::Windows::ADSI.create(name, @object_class))
end

.current_sam_compatible_user_nameObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


540
541
542
# File 'lib/puppet/util/windows/adsi.rb', line 540

def self.current_sam_compatible_user_name
  current_user_name_with_format(NameSamCompatible)
end

.current_user_nameObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
# File 'lib/puppet/util/windows/adsi.rb', line 489

def self.current_user_name
  user_name = ''
  max_length = MAX_USERNAME_LENGTH + 1 # NULL terminated
  FFI::MemoryPointer.new(max_length * 2) do |buffer| # wide string
    FFI::MemoryPointer.new(:dword, 1) do |buffer_size|
      buffer_size.write_dword(max_length) # length in TCHARs

      if GetUserNameW(buffer, buffer_size) == FFI::WIN32_FALSE
        raise Puppet::Util::Windows::Error.new(_("Failed to get user name"))
      end
      # buffer_size includes trailing NULL
      user_name = buffer.read_wide_string(buffer_size.read_dword - 1)
    end
  end

  user_name
end

.current_user_name_with_format(format) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
# File 'lib/puppet/util/windows/adsi.rb', line 521

def self.current_user_name_with_format(format)
  user_name = ''
  max_length = 1024

  FFI::MemoryPointer.new(:lpwstr, max_length * 2 + 1) do |buffer|
    FFI::MemoryPointer.new(:dword, 1) do |buffer_size|
      buffer_size.write_dword(max_length + 1)

      if GetUserNameExW(format.to_i, buffer, buffer_size) == FFI::WIN32_FALSE
        raise Puppet::Util::Windows::Error.new(_("Failed to get user name"), FFI.errno)
      end

      user_name = buffer.read_wide_string(buffer_size.read_dword).chomp
    end
  end

  user_name
end

.current_user_sidObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


544
545
546
# File 'lib/puppet/util/windows/adsi.rb', line 544

def self.current_user_sid
  Puppet::Util::Windows::SID.name_to_principal(current_user_name)
end

.list_allObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


303
304
305
# File 'lib/puppet/util/windows/adsi.rb', line 303

def list_all
  Puppet::Util::Windows::ADSI.execquery('select name from win32_useraccount where localaccount = "TRUE"')
end

.logon(name, password) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


307
308
309
# File 'lib/puppet/util/windows/adsi.rb', line 307

def logon(name, password)
  Puppet::Util::Windows::User.password_is?(name, password)
end

Instance Method Details

#add_flag(flag_name, value) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


322
323
324
325
326
327
328
# File 'lib/puppet/util/windows/adsi.rb', line 322

def add_flag(flag_name, value)
  flag = native_object.Get(flag_name) rescue 0

  native_object.Put(flag_name, flag | value)

  commit
end

#add_group_sids(*sids) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


364
365
366
367
# File 'lib/puppet/util/windows/adsi.rb', line 364

def add_group_sids(*sids)
  group_names = sids.map { |s| s. }
  add_to_groups(*group_names)
end

#add_to_groups(*group_names) ⇒ Object Also known as: add_to_group

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


349
350
351
352
353
# File 'lib/puppet/util/windows/adsi.rb', line 349

def add_to_groups(*group_names)
  group_names.each do |group_name|
    Puppet::Util::Windows::ADSI::Group.new(group_name).add_member_sids(sid)
  end
end

#disabled?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

467
468
469
# File 'lib/puppet/util/windows/adsi.rb', line 467

def disabled?
  userflag_set?(:ADS_UF_ACCOUNTDISABLE)
end

#expired?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

478
479
480
481
482
483
484
485
# File 'lib/puppet/util/windows/adsi.rb', line 478

def expired?
  expires = native_object.Get('AccountExpirationDate')
  expires && expires < Time.now
rescue WIN32OLERuntimeError => e
  # This OLE error code indicates the property can't be found in the cache
  raise e unless e.message =~ /8000500D/m
  false
end

#group_sidsObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


374
375
376
# File 'lib/puppet/util/windows/adsi.rb', line 374

def group_sids
  self.class.get_sids(native_object.Groups)
end

#groupsObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


340
341
342
343
344
345
346
347
# File 'lib/puppet/util/windows/adsi.rb', line 340

def groups
  # https://msdn.microsoft.com/en-us/library/aa746342.aspx
  # WIN32OLE objects aren't enumerable, so no map
  groups = []
  # Setting WIN32OLE.codepage ensures values are returned as UTF-8
  native_object.Groups.each {|g| groups << g.Name} rescue nil
  groups
end

#locked_out?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

471
472
473
474
475
476
# File 'lib/puppet/util/windows/adsi.rb', line 471

def locked_out?
  # Note that the LOCKOUT flag is known to be inaccurate when using the
  # LDAP IADsUser provider, but this class consistently uses the WinNT
  # provider, which is expected to be accurate.
  userflag_set?(:ADS_UF_LOCKOUT)
end

#op_userflags(*flags, &block) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Common helper for set_userflags and unset_userflags.


447
448
449
450
451
452
453
454
455
456
457
# File 'lib/puppet/util/windows/adsi.rb', line 447

def op_userflags(*flags, &block)
  # Avoid an unnecessary set + commit operation.
  return if flags.empty?

  unrecognized_flags = flags.reject { |flag| ADS_USERFLAGS.keys.include?(flag) }
  unless unrecognized_flags.empty?
    raise ArgumentError, _("Unrecognized ADS UserFlags: %{unrecognized_flags}") % { unrecognized_flags: unrecognized_flags.join(', ') }
  end

  self['UserFlags'] = flags.inject(self['UserFlags'], &block)
end

#password=(password) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


330
331
332
333
334
335
336
337
338
# File 'lib/puppet/util/windows/adsi.rb', line 330

def password=(password)
  if !password.nil?
    native_object.SetPassword(password)
    commit
  end

  fADS_UF_DONT_EXPIRE_PASSWD = 0x10000
  add_flag("UserFlags", fADS_UF_DONT_EXPIRE_PASSWD)
end

#password_is?(password) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

318
319
320
# File 'lib/puppet/util/windows/adsi.rb', line 318

def password_is?(password)
  self.class.logon(name, password)
end

#remove_from_groups(*group_names) ⇒ Object Also known as: remove_from_group

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


356
357
358
359
360
# File 'lib/puppet/util/windows/adsi.rb', line 356

def remove_from_groups(*group_names)
  group_names.each do |group_name|
    Puppet::Util::Windows::ADSI::Group.new(group_name).remove_member_sids(sid)
  end
end

#remove_group_sids(*sids) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


369
370
371
372
# File 'lib/puppet/util/windows/adsi.rb', line 369

def remove_group_sids(*sids)
  group_names = sids.map { |s| s. }
  remove_from_groups(*group_names)
end

#set_groups(desired_groups, minimum = true) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

TODO: This code's pretty similar to set_members in the Group class. Would be nice to refactor them into the ADSIObject class at some point. This was not done originally because these use different methods to do stuff that are also aliased to other methods, so the shared code isn't exactly a 1:1 mapping.


382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# File 'lib/puppet/util/windows/adsi.rb', line 382

def set_groups(desired_groups, minimum = true)
  return if desired_groups.nil?

  desired_groups = desired_groups.split(',').map(&:strip)

  current_hash = Hash[ self.group_sids.map { |sid| [sid.sid, sid] } ]
  desired_hash = self.class.name_sid_hash(desired_groups)

  # First we add the user to all the groups it should be in but isn't
  if !desired_groups.empty?
    groups_to_add = (desired_hash.keys - current_hash.keys).map { |sid| desired_hash[sid] }
    add_group_sids(*groups_to_add)
  end

  # Then we remove the user from all groups it is in but shouldn't be, if
  # that's been requested
  if !minimum
    if desired_hash.empty?
      groups_to_remove = current_hash.values
    else
      groups_to_remove = (current_hash.keys - desired_hash.keys).map { |sid| current_hash[sid] }
    end

    remove_group_sids(*groups_to_remove)
  end
end

#set_userflags(*flags) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


459
460
461
# File 'lib/puppet/util/windows/adsi.rb', line 459

def set_userflags(*flags)
  op_userflags(*flags) { |userflags, flag| userflags | ADS_USERFLAGS[flag] }
end

#unset_userflags(*flags) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


463
464
465
# File 'lib/puppet/util/windows/adsi.rb', line 463

def unset_userflags(*flags)
  op_userflags(*flags) { |userflags, flag| userflags & ~ADS_USERFLAGS[flag] }
end

#userflag_set?(flag) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

439
440
441
442
# File 'lib/puppet/util/windows/adsi.rb', line 439

def userflag_set?(flag)
  flag_value = ADS_USERFLAGS[flag] || 0
  ! (self['UserFlags'] & flag_value).zero?
end