Module: Puppet::Util::Windows::User

Extended by:
FFI::Library, String
Defined in:
lib/puppet/util/windows/user.rb

Defined Under Namespace

Classes: LSA_OBJECT_ATTRIBUTES, LSA_UNICODE_STRING, PROFILEINFO

Constant Summary collapse

SECURITY_MAX_SID_SIZE =
68
ERROR_ACCOUNT_RESTRICTION =

msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx These error codes indicate successful authentication but failure to logon for a separate reason

1327
ERROR_INVALID_LOGON_HOURS =
1328
ERROR_INVALID_WORKSTATION =
1329
ERROR_ACCOUNT_DISABLED =
1331
POLICY_VIEW_LOCAL_INFORMATION =
0x00000001
POLICY_VIEW_AUDIT_INFORMATION =
0x00000002
POLICY_GET_PRIVATE_INFORMATION =
0x00000004
POLICY_TRUST_ADMIN =
0x00000008
POLICY_CREATE_ACCOUNT =
0x00000010
POLICY_CREATE_SECRET =
0x00000020
POLICY_CREATE_PRIVILEGE =
0x00000040
POLICY_SET_DEFAULT_QUOTA_LIMITS =
0x00000080
POLICY_SET_AUDIT_REQUIREMENTS =
0x00000100
POLICY_AUDIT_LOG_ADMIN =
0x00000200
POLICY_SERVER_ADMIN =
0x00000400
POLICY_LOOKUP_NAMES =
0x00000800
POLICY_NOTIFICATION =
0x00001000
WELL_KNOWN_SID_TYPE =
enum(
  :WinNullSid                                   , 0,
  :WinWorldSid                                  , 1,
  :WinLocalSid                                  , 2,
  :WinCreatorOwnerSid                           , 3,
  :WinCreatorGroupSid                           , 4,
  :WinCreatorOwnerServerSid                     , 5,
  :WinCreatorGroupServerSid                     , 6,
  :WinNtAuthoritySid                            , 7,
  :WinDialupSid                                 , 8,
  :WinNetworkSid                                , 9,
  :WinBatchSid                                  , 10,
  :WinInteractiveSid                            , 11,
  :WinServiceSid                                , 12,
  :WinAnonymousSid                              , 13,
  :WinProxySid                                  , 14,
  :WinEnterpriseControllersSid                  , 15,
  :WinSelfSid                                   , 16,
  :WinAuthenticatedUserSid                      , 17,
  :WinRestrictedCodeSid                         , 18,
  :WinTerminalServerSid                         , 19,
  :WinRemoteLogonIdSid                          , 20,
  :WinLogonIdsSid                               , 21,
  :WinLocalSystemSid                            , 22,
  :WinLocalServiceSid                           , 23,
  :WinNetworkServiceSid                         , 24,
  :WinBuiltinDomainSid                          , 25,
  :WinBuiltinAdministratorsSid                  , 26,
  :WinBuiltinUsersSid                           , 27,
  :WinBuiltinGuestsSid                          , 28,
  :WinBuiltinPowerUsersSid                      , 29,
  :WinBuiltinAccountOperatorsSid                , 30,
  :WinBuiltinSystemOperatorsSid                 , 31,
  :WinBuiltinPrintOperatorsSid                  , 32,
  :WinBuiltinBackupOperatorsSid                 , 33,
  :WinBuiltinReplicatorSid                      , 34,
  :WinBuiltinPreWindows2000CompatibleAccessSid  , 35,
  :WinBuiltinRemoteDesktopUsersSid              , 36,
  :WinBuiltinNetworkConfigurationOperatorsSid   , 37,
  :WinAccountAdministratorSid                   , 38,
  :WinAccountGuestSid                           , 39,
  :WinAccountKrbtgtSid                          , 40,
  :WinAccountDomainAdminsSid                    , 41,
  :WinAccountDomainUsersSid                     , 42,
  :WinAccountDomainGuestsSid                    , 43,
  :WinAccountComputersSid                       , 44,
  :WinAccountControllersSid                     , 45,
  :WinAccountCertAdminsSid                      , 46,
  :WinAccountSchemaAdminsSid                    , 47,
  :WinAccountEnterpriseAdminsSid                , 48,
  :WinAccountPolicyAdminsSid                    , 49,
  :WinAccountRasAndIasServersSid                , 50,
  :WinNTLMAuthenticationSid                     , 51,
  :WinDigestAuthenticationSid                   , 52,
  :WinSChannelAuthenticationSid                 , 53,
  :WinThisOrganizationSid                       , 54,
  :WinOtherOrganizationSid                      , 55,
  :WinBuiltinIncomingForestTrustBuildersSid     , 56,
  :WinBuiltinPerfMonitoringUsersSid             , 57,
  :WinBuiltinPerfLoggingUsersSid                , 58,
  :WinBuiltinAuthorizationAccessSid             , 59,
  :WinBuiltinTerminalServerLicenseServersSid    , 60,
  :WinBuiltinDCOMUsersSid                       , 61,
  :WinBuiltinIUsersSid                          , 62,
  :WinIUserSid                                  , 63,
  :WinBuiltinCryptoOperatorsSid                 , 64,
  :WinUntrustedLabelSid                         , 65,
  :WinLowLabelSid                               , 66,
  :WinMediumLabelSid                            , 67,
  :WinHighLabelSid                              , 68,
  :WinSystemLabelSid                            , 69,
  :WinWriteRestrictedCodeSid                    , 70,
  :WinCreatorOwnerRightsSid                     , 71,
  :WinCacheablePrincipalsGroupSid               , 72,
  :WinNonCacheablePrincipalsGroupSid            , 73,
  :WinEnterpriseReadonlyControllersSid          , 74,
  :WinAccountReadonlyControllersSid             , 75,
  :WinBuiltinEventLogReadersGroup               , 76,
  :WinNewEnterpriseReadonlyControllersSid       , 77,
  :WinBuiltinCertSvcDComAccessGroup             , 78,
  :WinMediumPlusLabelSid                        , 79,
  :WinLocalLogonSid                             , 80,
  :WinConsoleLogonSid                           , 81,
  :WinThisOrganizationCertificateSid            , 82,
  :WinApplicationPackageAuthoritySid            , 83,
  :WinBuiltinAnyPackageSid                      , 84,
  :WinCapabilityInternetClientSid               , 85,
  :WinCapabilityInternetClientServerSid         , 86,
  :WinCapabilityPrivateNetworkClientServerSid   , 87,
  :WinCapabilityPicturesLibrarySid              , 88,
  :WinCapabilityVideosLibrarySid                , 89,
  :WinCapabilityMusicLibrarySid                 , 90,
  :WinCapabilityDocumentsLibrarySid             , 91,
  :WinCapabilitySharedUserCertificatesSid       , 92,
  :WinCapabilityEnterpriseAuthenticationSid     , 93,
  :WinCapabilityRemovableStorageSid             , 94
)

Class Method Summary collapse

Methods included from String

wide_string

Class Method Details

.admin?Boolean

Returns:

  • (Boolean)


11
12
13
14
15
16
17
# File 'lib/puppet/util/windows/user.rb', line 11

def admin?
  return false unless check_token_membership

  # if Vista or later, check for unrestricted process token
  elevated_supported = Puppet::Util::Windows::Process.supports_elevated_security?
  return elevated_supported ? Puppet::Util::Windows::Process.elevated_security? : true
end

.check_token_membershipObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/puppet/util/windows/user.rb', line 48

def check_token_membership
  is_admin = false
  FFI::MemoryPointer.new(:byte, SECURITY_MAX_SID_SIZE) do |sid_pointer|
    FFI::MemoryPointer.new(:dword, 1) do |size_pointer|
      size_pointer.write_uint32(SECURITY_MAX_SID_SIZE)

      if CreateWellKnownSid(:WinBuiltinAdministratorsSid, FFI::Pointer::NULL, sid_pointer, size_pointer) == FFI::WIN32_FALSE
        raise Puppet::Util::Windows::Error.new(_("Failed to create administrators SID"))
      end
    end

    if IsValidSid(sid_pointer) == FFI::WIN32_FALSE
      raise Puppet::Util::Windows::Error.new(_("Invalid SID"))
    end

    FFI::MemoryPointer.new(:win32_bool, 1) do |ismember_pointer|
      if CheckTokenMembership(FFI::Pointer::NULL_HANDLE, sid_pointer, ismember_pointer) == FFI::WIN32_FALSE
        raise Puppet::Util::Windows::Error.new(_("Failed to check membership"))
      end

      # Is administrators SID enabled in calling thread's access token?
      is_admin = ismember_pointer.read_win32_bool
    end
  end

  is_admin
end

.default_system_account?(name) ⇒ Boolean

Check if a given user is one of the default system accounts These accounts do not have a password and all checks done through logon attempt will fail docs.microsoft.com/en-us/windows/security/identity-protection/access-control/local-accounts#default-local-system-accounts

Returns:

  • (Boolean)


31
32
33
34
# File 'lib/puppet/util/windows/user.rb', line 31

def default_system_account?(name)
  user_sid = Puppet::Util::Windows::SID.name_to_sid(name)
  [Puppet::Util::Windows::SID::LocalSystem, Puppet::Util::Windows::SID::NtLocal, Puppet::Util::Windows::SID::NtNetwork].include?(user_sid)
end

.get_rights(name) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/puppet/util/windows/user.rb', line 148

def get_rights(name)
   = Puppet::Util::Windows::SID.name_to_principal(name.sub(/^\.\\/, "#{Puppet::Util::Windows::ADSI.computer_name}\\"))
  return "" unless 

  rights = []
  rights_pointer = FFI::MemoryPointer.new(:pointer)
  number_of_rights = FFI::MemoryPointer.new(:ulong)
  sid_pointer = FFI::MemoryPointer.new(:byte, .sid_bytes.length).write_array_of_uchar(.sid_bytes)

  new_lsa_policy_handle do |policy_handle|
    result = LsaEnumerateAccountRights(policy_handle.read_pointer, sid_pointer, rights_pointer, number_of_rights)
    check_lsa_nt_status_and_raise_failures(result, "LsaEnumerateAccountRights")
  end

  number_of_rights.read_ulong.times do |index|
    right = LSA_UNICODE_STRING.new(rights_pointer.read_pointer + index * LSA_UNICODE_STRING.size)
    rights << right[:Buffer].read_arbitrary_wide_string_up_to
  end

  result = LsaFreeMemory(rights_pointer.read_pointer)
  check_lsa_nt_status_and_raise_failures(result, "LsaFreeMemory")

  rights.join(",")
end

.load_profile(user, password) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/puppet/util/windows/user.rb', line 125

def load_profile(user, password)
  logon_user(user, password) do |token|
    FFI::MemoryPointer.from_string_to_wide_string(user) do |lpUserName|
      pi = PROFILEINFO.new
      pi[:dwSize] = PROFILEINFO.size
      pi[:dwFlags] = 1 # PI_NOUI - prevents display of profile error msgs
      pi[:lpUserName] = lpUserName

      # Load the profile. Since it doesn't exist, it will be created
      if LoadUserProfileW(token, pi.pointer) == FFI::WIN32_FALSE
        raise Puppet::Util::Windows::Error.new(_("Failed to load user profile %{user}") % { user: user.inspect })
      end

      Puppet.debug("Loaded profile for #{user}")

      if UnloadUserProfile(token, pi[:hProfile]) == FFI::WIN32_FALSE
        raise Puppet::Util::Windows::Error.new(_("Failed to unload user profile %{user}") % { user: user.inspect })
      end
    end
  end
end

.localsystem?(name) ⇒ Boolean

The name of the account in all locales is ‘LocalSystem`. `.LocalSystem` or `ComputerNameLocalSystem’ can also be used. This account is not recognized by the security subsystem, so you cannot specify its name in a call to the ‘LookupAccountName` function. docs.microsoft.com/en-us/windows/win32/services/localsystem-account

Returns:

  • (Boolean)


23
24
25
# File 'lib/puppet/util/windows/user.rb', line 23

def localsystem?(name)
  ["LocalSystem", ".\\LocalSystem", "#{Puppet::Util::Windows::ADSI.computer_name}\\LocalSystem"].any? { |s| s.casecmp(name) == 0 }
end

.logon_user(name, password, domain = '.', &block) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/puppet/util/windows/user.rb', line 93

def logon_user(name, password, domain = '.', &block)
  fLOGON32_PROVIDER_DEFAULT = 0
  fLOGON32_LOGON_INTERACTIVE = 2
  fLOGON32_LOGON_NETWORK = 3

  token = nil
  begin
    FFI::MemoryPointer.new(:handle, 1) do |token_pointer|
      # try logon using network else try logon using interactive mode
      if logon_user_by_logon_type(name, domain, password, fLOGON32_LOGON_NETWORK, fLOGON32_PROVIDER_DEFAULT, token_pointer) == FFI::WIN32_FALSE
        if logon_user_by_logon_type(name, domain, password, fLOGON32_LOGON_INTERACTIVE, fLOGON32_PROVIDER_DEFAULT, token_pointer) == FFI::WIN32_FALSE
          raise Puppet::Util::Windows::Error.new(_("Failed to logon user %{name}") % { name: name.inspect })
        end
      end

      yield token = token_pointer.read_handle
    end
  ensure
    FFI::WIN32.CloseHandle(token) if token
  end

  # token has been closed by this point
  true
end

.password_is?(name, password, domain = '.') ⇒ Boolean

Returns:

  • (Boolean)


77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/puppet/util/windows/user.rb', line 77

def password_is?(name, password, domain = '.')
  begin
    logon_user(name, password, domain) { |token| }
  rescue Puppet::Util::Windows::Error => detail
    authenticated_error_codes = Set[
      ERROR_ACCOUNT_RESTRICTION,
      ERROR_INVALID_LOGON_HOURS,
      ERROR_INVALID_WORKSTATION,
      ERROR_ACCOUNT_DISABLED,
    ]

    return authenticated_error_codes.include?(detail.code)
  end
end

.remove_rights(name, rights) ⇒ Object



186
187
188
189
190
191
192
193
194
195
# File 'lib/puppet/util/windows/user.rb', line 186

def remove_rights(name, rights)
  rights_pointer = new_lsa_unicode_strings_pointer(rights)
   = Puppet::Util::Windows::SID.name_to_principal(name.sub(/^\.\\/, "#{Puppet::Util::Windows::ADSI.computer_name}\\"))
  sid_pointer = FFI::MemoryPointer.new(:byte, .sid_bytes.length).write_array_of_uchar(.sid_bytes)

  new_lsa_policy_handle do |policy_handle|
    result = LsaRemoveAccountRights(policy_handle.read_pointer, sid_pointer, false, rights_pointer, rights.size)
    check_lsa_nt_status_and_raise_failures(result, "LsaRemoveAccountRights")
  end
end

.set_rights(name, rights) ⇒ Object



174
175
176
177
178
179
180
181
182
183
# File 'lib/puppet/util/windows/user.rb', line 174

def set_rights(name, rights)
  rights_pointer = new_lsa_unicode_strings_pointer(rights)
   = Puppet::Util::Windows::SID.name_to_principal(name.sub(/^\.\\/, "#{Puppet::Util::Windows::ADSI.computer_name}\\"))
  sid_pointer = FFI::MemoryPointer.new(:byte, .sid_bytes.length).write_array_of_uchar(.sid_bytes)

  new_lsa_policy_handle do |policy_handle|
    result = LsaAddAccountRights(policy_handle.read_pointer, sid_pointer, rights_pointer, rights.size)
    check_lsa_nt_status_and_raise_failures(result, "LsaAddAccountRights")
  end
end