module Puppet::Util::Windows::SID
Constants
- AccountOperators
- AllAppPackages
- Anonymous
- AuthenticatedUsers
- BackupOperators
- Batch
- BuiltinAdministrators
- BuiltinUsers
- Creator
- CreatorGroup
- CreatorGroupServer
- CreatorOwner
- CreatorOwnerServer
- Dialup
- ERROR_INVALID_SID_STRUCTURE
- ERROR_NONE_MAPPED
missing from
Windows::Error
- EnterpriseDomainControllers
- Everyone
- Guests
- Interactive
- Local
- LocalSystem
- MAXIMUM_SID_STRING_LENGTH
stackoverflow.com/a/1792930 - 68 bytes, 184 characters in a string
- Network
- Nobody
- NonUnique
- Nt
- NtLocal
- NtNetwork
- Null
Well Known SIDs
- PowerUsers
- PrincipalSelf
- PrintOperators
- Proxy
- Replicators
- RestrictedCode
- ServerOperators
- Service
- TerminalServerUsers
- World
Public Class Methods
Converts a COM
instance of IAdsUser or IAdsGroup to a SID::Principal
object, Raises an Error
for nil or an object without an objectSID / Name property. This method returns a SID::Principal
with the account, domain, SID
, etc This method will return instances even when the SID
is unresolvable, as may be the case when domain users have been added to local groups, but removed from the domain
# File lib/puppet/util/windows/sid.rb 112 def ads_to_principal(ads_object) 113 if !ads_object || !ads_object.respond_to?(:ole_respond_to?) || 114 !ads_object.ole_respond_to?(:objectSID) || !ads_object.ole_respond_to?(:Name) 115 raise Puppet::Error.new("ads_object must be an IAdsUser or IAdsGroup instance") 116 end 117 octet_string_to_principal(ads_object.objectSID) 118 rescue Puppet::Util::Windows::Error => e 119 # if the error is not a lookup / mapping problem, immediately re-raise 120 raise if e.code != ERROR_NONE_MAPPED 121 122 # if the Name property isn't formatted like a SID, OR 123 if !valid_sid?(ads_object.Name) || 124 # if the objectSID doesn't match the Name property, also raise 125 ((converted = octet_string_to_sid_string(ads_object.objectSID)) != ads_object.Name) 126 raise Puppet::Error.new("ads_object Name: #{ads_object.Name} invalid or does not match objectSID: #{ads_object.objectSID} (#{converted})", e) 127 end 128 129 unresolved_principal(ads_object.Name, ads_object.objectSID) 130 end
# File lib/puppet/util/windows/sid.rb 218 def get_length_sid(sid_ptr) 219 # MSDN states IsValidSid should be called on pointer first 220 if ! sid_ptr.kind_of?(FFI::Pointer) || IsValidSid(sid_ptr) == FFI::WIN32_FALSE 221 raise Puppet::Util::Windows::Error.new(_("Invalid SID")) 222 end 223 224 GetLengthSid(sid_ptr) 225 end
Convert an account name, e.g. 'Administrators' into a Principal::SID object, e.g. 'S-1-5-32-544'. The name can be specified as 'Administrators', 'BUILTINAdministrators', or 'S-1-5-32-544', and will return the SID
object. Returns nil if the account doesn't exist. This method returns a SID::Principal
with the account, domain, SID
, etc
# File lib/puppet/util/windows/sid.rb 67 def name_to_principal(name, allow_unresolved = false) 68 # Apparently, we accept a symbol.. 69 name = name.to_s.strip if name 70 71 # if name is a SID string, convert it to raw bytes for use with lookup_account_sid 72 raw_sid_bytes = nil 73 begin 74 string_to_sid_ptr(name) do |sid_ptr| 75 raw_sid_bytes = sid_ptr.read_array_of_uchar(get_length_sid(sid_ptr)) 76 end 77 rescue => e 78 # Avoid debug logs pollution with valid account names 79 # https://docs.microsoft.com/en-us/windows/win32/api/sddl/nf-sddl-convertstringsidtosidw#return-value 80 Puppet.debug("Could not retrieve raw SID bytes from '#{name}': #{e.message}") unless e.code == ERROR_INVALID_SID_STRUCTURE 81 end 82 83 raw_sid_bytes ? Principal.lookup_account_sid(raw_sid_bytes) : Principal.lookup_account_name(name) 84 rescue => e 85 Puppet.debug("#{e.message}") 86 (allow_unresolved && raw_sid_bytes) ? unresolved_principal(name, raw_sid_bytes) : nil 87 end
Convert an account name, e.g. 'Administrators' into a SID
string, e.g. 'S-1-5-32-544'. The name can be specified as 'Administrators', 'BUILTINAdministrators', or 'S-1-5-32-544', and will return the SID
. Returns nil if the account doesn't exist.
# File lib/puppet/util/windows/sid.rb 55 def name_to_sid(name) 56 sid = name_to_principal(name) 57 58 sid ? sid.sid : nil 59 end
Converts an octet string array of bytes to a SID::Principal
object, e.g. [1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0] is the representation for S-1-5-18, the local 'SYSTEM' account. Raises an Error
for nil or non-array input. This method returns a SID::Principal
with the account, domain, SID
, etc
# File lib/puppet/util/windows/sid.rb 96 def octet_string_to_principal(bytes) 97 if !bytes || !bytes.respond_to?('pack') || bytes.empty? 98 raise Puppet::Util::Windows::Error.new(_("Octet string must be an array of bytes")) 99 end 100 101 Principal.lookup_account_sid(bytes) 102 end
# File lib/puppet/util/windows/sid.rb 228 def octet_string_to_sid_string(sid_bytes) 229 sid_string = nil 230 231 FFI::MemoryPointer.new(:byte, sid_bytes.length) do |sid_ptr| 232 sid_ptr.write_array_of_uchar(sid_bytes) 233 sid_string = Puppet::Util::Windows::SID.sid_ptr_to_string(sid_ptr) 234 end 235 236 sid_string 237 end
Convert a SID
pointer to a SID
string, e.g. “S-1-5-32-544”.
# File lib/puppet/util/windows/sid.rb 157 def sid_ptr_to_string(psid) 158 if ! psid.kind_of?(FFI::Pointer) || IsValidSid(psid) == FFI::WIN32_FALSE 159 raise Puppet::Util::Windows::Error.new(_("Invalid SID")) 160 end 161 162 sid_string = nil 163 FFI::MemoryPointer.new(:pointer, 1) do |buffer_ptr| 164 if ConvertSidToStringSidW(psid, buffer_ptr) == FFI::WIN32_FALSE 165 raise Puppet::Util::Windows::Error.new(_("Failed to convert binary SID")) 166 end 167 168 buffer_ptr.read_win32_local_pointer do |wide_string_ptr| 169 if wide_string_ptr.null? 170 raise Puppet::Error.new(_("ConvertSidToStringSidW failed to allocate buffer for sid")) 171 end 172 173 sid_string = wide_string_ptr.read_arbitrary_wide_string_up_to(MAXIMUM_SID_STRING_LENGTH) 174 end 175 end 176 177 sid_string 178 end
Convert a SID
string, e.g. “S-1-5-32-544” to a name, e.g. 'BUILTINAdministrators'. Returns nil if an account for that SID
does not exist.
# File lib/puppet/util/windows/sid.rb 136 def sid_to_name(value) 137 138 sid_bytes = [] 139 begin 140 string_to_sid_ptr(value) do |ptr| 141 sid_bytes = ptr.read_array_of_uchar(get_length_sid(ptr)) 142 end 143 rescue Puppet::Util::Windows::Error => e 144 raise if e.code != ERROR_INVALID_SID_STRUCTURE 145 end 146 147 Principal.lookup_account_sid(sid_bytes).domain_account 148 rescue 149 nil 150 end
Convert a SID
string, e.g. “S-1-5-32-544” to a pointer (containing the address of the binary SID
structure). The returned value can be used in Win32 APIs that expect a PSID, e.g. IsValidSid. The account for this SID
may or may not exist.
# File lib/puppet/util/windows/sid.rb 185 def string_to_sid_ptr(string_sid, &block) 186 FFI::MemoryPointer.from_string_to_wide_string(string_sid) do |lpcwstr| 187 FFI::MemoryPointer.new(:pointer, 1) do |sid_ptr_ptr| 188 189 if ConvertStringSidToSidW(lpcwstr, sid_ptr_ptr) == FFI::WIN32_FALSE 190 raise Puppet::Util::Windows::Error.new(_("Failed to convert string SID: %{string_sid}") % { string_sid: string_sid }) 191 end 192 193 sid_ptr_ptr.read_win32_local_pointer do |sid_ptr| 194 yield sid_ptr 195 end 196 end 197 end 198 199 # yielded sid_ptr has already had LocalFree called, nothing to return 200 nil 201 end
@api private
# File lib/puppet/util/windows/sid.rb 241 def self.unresolved_principal(name, sid_bytes) 242 Principal.new( 243 name, # account 244 sid_bytes, # sid_bytes 245 name, # sid string 246 nil, #domain 247 # https://msdn.microsoft.com/en-us/library/cc245534.aspx?f=255&MSPPError=-2147217396 248 # Indicates that the type of object could not be determined. For example, no object with that SID exists. 249 :SidTypeUnknown) 250 end
Return true if the string is a valid SID
, e.g. “S-1-5-32-544”, false otherwise.
# File lib/puppet/util/windows/sid.rb 205 def valid_sid?(string_sid) 206 valid = false 207 208 begin 209 string_to_sid_ptr(string_sid) { |ptr| valid = ! ptr.nil? && ! ptr.null? } 210 rescue Puppet::Util::Windows::Error => e 211 raise if e.code != ERROR_INVALID_SID_STRUCTURE 212 end 213 214 valid 215 end
Private Instance Methods
Converts a COM
instance of IAdsUser or IAdsGroup to a SID::Principal
object, Raises an Error
for nil or an object without an objectSID / Name property. This method returns a SID::Principal
with the account, domain, SID
, etc This method will return instances even when the SID
is unresolvable, as may be the case when domain users have been added to local groups, but removed from the domain
# File lib/puppet/util/windows/sid.rb 112 def ads_to_principal(ads_object) 113 if !ads_object || !ads_object.respond_to?(:ole_respond_to?) || 114 !ads_object.ole_respond_to?(:objectSID) || !ads_object.ole_respond_to?(:Name) 115 raise Puppet::Error.new("ads_object must be an IAdsUser or IAdsGroup instance") 116 end 117 octet_string_to_principal(ads_object.objectSID) 118 rescue Puppet::Util::Windows::Error => e 119 # if the error is not a lookup / mapping problem, immediately re-raise 120 raise if e.code != ERROR_NONE_MAPPED 121 122 # if the Name property isn't formatted like a SID, OR 123 if !valid_sid?(ads_object.Name) || 124 # if the objectSID doesn't match the Name property, also raise 125 ((converted = octet_string_to_sid_string(ads_object.objectSID)) != ads_object.Name) 126 raise Puppet::Error.new("ads_object Name: #{ads_object.Name} invalid or does not match objectSID: #{ads_object.objectSID} (#{converted})", e) 127 end 128 129 unresolved_principal(ads_object.Name, ads_object.objectSID) 130 end
# File lib/puppet/util/windows/sid.rb 218 def get_length_sid(sid_ptr) 219 # MSDN states IsValidSid should be called on pointer first 220 if ! sid_ptr.kind_of?(FFI::Pointer) || IsValidSid(sid_ptr) == FFI::WIN32_FALSE 221 raise Puppet::Util::Windows::Error.new(_("Invalid SID")) 222 end 223 224 GetLengthSid(sid_ptr) 225 end
Convert an account name, e.g. 'Administrators' into a Principal::SID object, e.g. 'S-1-5-32-544'. The name can be specified as 'Administrators', 'BUILTINAdministrators', or 'S-1-5-32-544', and will return the SID
object. Returns nil if the account doesn't exist. This method returns a SID::Principal
with the account, domain, SID
, etc
# File lib/puppet/util/windows/sid.rb 67 def name_to_principal(name, allow_unresolved = false) 68 # Apparently, we accept a symbol.. 69 name = name.to_s.strip if name 70 71 # if name is a SID string, convert it to raw bytes for use with lookup_account_sid 72 raw_sid_bytes = nil 73 begin 74 string_to_sid_ptr(name) do |sid_ptr| 75 raw_sid_bytes = sid_ptr.read_array_of_uchar(get_length_sid(sid_ptr)) 76 end 77 rescue => e 78 # Avoid debug logs pollution with valid account names 79 # https://docs.microsoft.com/en-us/windows/win32/api/sddl/nf-sddl-convertstringsidtosidw#return-value 80 Puppet.debug("Could not retrieve raw SID bytes from '#{name}': #{e.message}") unless e.code == ERROR_INVALID_SID_STRUCTURE 81 end 82 83 raw_sid_bytes ? Principal.lookup_account_sid(raw_sid_bytes) : Principal.lookup_account_name(name) 84 rescue => e 85 Puppet.debug("#{e.message}") 86 (allow_unresolved && raw_sid_bytes) ? unresolved_principal(name, raw_sid_bytes) : nil 87 end
Convert an account name, e.g. 'Administrators' into a SID
string, e.g. 'S-1-5-32-544'. The name can be specified as 'Administrators', 'BUILTINAdministrators', or 'S-1-5-32-544', and will return the SID
. Returns nil if the account doesn't exist.
# File lib/puppet/util/windows/sid.rb 55 def name_to_sid(name) 56 sid = name_to_principal(name) 57 58 sid ? sid.sid : nil 59 end
Converts an octet string array of bytes to a SID::Principal
object, e.g. [1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0] is the representation for S-1-5-18, the local 'SYSTEM' account. Raises an Error
for nil or non-array input. This method returns a SID::Principal
with the account, domain, SID
, etc
# File lib/puppet/util/windows/sid.rb 96 def octet_string_to_principal(bytes) 97 if !bytes || !bytes.respond_to?('pack') || bytes.empty? 98 raise Puppet::Util::Windows::Error.new(_("Octet string must be an array of bytes")) 99 end 100 101 Principal.lookup_account_sid(bytes) 102 end
# File lib/puppet/util/windows/sid.rb 228 def octet_string_to_sid_string(sid_bytes) 229 sid_string = nil 230 231 FFI::MemoryPointer.new(:byte, sid_bytes.length) do |sid_ptr| 232 sid_ptr.write_array_of_uchar(sid_bytes) 233 sid_string = Puppet::Util::Windows::SID.sid_ptr_to_string(sid_ptr) 234 end 235 236 sid_string 237 end
Convert a SID
pointer to a SID
string, e.g. “S-1-5-32-544”.
# File lib/puppet/util/windows/sid.rb 157 def sid_ptr_to_string(psid) 158 if ! psid.kind_of?(FFI::Pointer) || IsValidSid(psid) == FFI::WIN32_FALSE 159 raise Puppet::Util::Windows::Error.new(_("Invalid SID")) 160 end 161 162 sid_string = nil 163 FFI::MemoryPointer.new(:pointer, 1) do |buffer_ptr| 164 if ConvertSidToStringSidW(psid, buffer_ptr) == FFI::WIN32_FALSE 165 raise Puppet::Util::Windows::Error.new(_("Failed to convert binary SID")) 166 end 167 168 buffer_ptr.read_win32_local_pointer do |wide_string_ptr| 169 if wide_string_ptr.null? 170 raise Puppet::Error.new(_("ConvertSidToStringSidW failed to allocate buffer for sid")) 171 end 172 173 sid_string = wide_string_ptr.read_arbitrary_wide_string_up_to(MAXIMUM_SID_STRING_LENGTH) 174 end 175 end 176 177 sid_string 178 end
Convert a SID
string, e.g. “S-1-5-32-544” to a name, e.g. 'BUILTINAdministrators'. Returns nil if an account for that SID
does not exist.
# File lib/puppet/util/windows/sid.rb 136 def sid_to_name(value) 137 138 sid_bytes = [] 139 begin 140 string_to_sid_ptr(value) do |ptr| 141 sid_bytes = ptr.read_array_of_uchar(get_length_sid(ptr)) 142 end 143 rescue Puppet::Util::Windows::Error => e 144 raise if e.code != ERROR_INVALID_SID_STRUCTURE 145 end 146 147 Principal.lookup_account_sid(sid_bytes).domain_account 148 rescue 149 nil 150 end
Convert a SID
string, e.g. “S-1-5-32-544” to a pointer (containing the address of the binary SID
structure). The returned value can be used in Win32 APIs that expect a PSID, e.g. IsValidSid. The account for this SID
may or may not exist.
# File lib/puppet/util/windows/sid.rb 185 def string_to_sid_ptr(string_sid, &block) 186 FFI::MemoryPointer.from_string_to_wide_string(string_sid) do |lpcwstr| 187 FFI::MemoryPointer.new(:pointer, 1) do |sid_ptr_ptr| 188 189 if ConvertStringSidToSidW(lpcwstr, sid_ptr_ptr) == FFI::WIN32_FALSE 190 raise Puppet::Util::Windows::Error.new(_("Failed to convert string SID: %{string_sid}") % { string_sid: string_sid }) 191 end 192 193 sid_ptr_ptr.read_win32_local_pointer do |sid_ptr| 194 yield sid_ptr 195 end 196 end 197 end 198 199 # yielded sid_ptr has already had LocalFree called, nothing to return 200 nil 201 end
Return true if the string is a valid SID
, e.g. “S-1-5-32-544”, false otherwise.
# File lib/puppet/util/windows/sid.rb 205 def valid_sid?(string_sid) 206 valid = false 207 208 begin 209 string_to_sid_ptr(string_sid) { |ptr| valid = ! ptr.nil? && ! ptr.null? } 210 rescue Puppet::Util::Windows::Error => e 211 raise if e.code != ERROR_INVALID_SID_STRUCTURE 212 end 213 214 valid 215 end