Module: Puppet::Util::Windows::SID
- Extended by:
- FFI::Library
- Included in:
- AccessControlEntry, SecurityDescriptor
- Defined in:
- lib/puppet/util/windows.rb,
lib/puppet/util/windows/sid.rb,
lib/puppet/util/windows/principal.rb
Defined Under Namespace
Classes: Principal
Constant Summary collapse
- ERROR_NONE_MAPPED =
missing from Windows::Error
1332
- ERROR_INVALID_SID_STRUCTURE =
1337
- ERROR_TRUSTED_DOMAIN_FAILURE =
1788
- ERROR_TRUSTED_RELATIONSHIP_FAILURE =
1789
- Null =
Well Known SIDs
'S-1-0'
- Nobody =
'S-1-0-0'
- World =
'S-1-1'
- Everyone =
'S-1-1-0'
- Local =
'S-1-2'
- Creator =
'S-1-3'
- CreatorOwner =
'S-1-3-0'
- CreatorGroup =
'S-1-3-1'
- CreatorOwnerServer =
'S-1-3-2'
- CreatorGroupServer =
'S-1-3-3'
- NonUnique =
'S-1-4'
- Nt =
'S-1-5'
- Dialup =
'S-1-5-1'
- Network =
'S-1-5-2'
- Batch =
'S-1-5-3'
- Interactive =
'S-1-5-4'
- Service =
'S-1-5-6'
- Anonymous =
'S-1-5-7'
- Proxy =
'S-1-5-8'
- EnterpriseDomainControllers =
'S-1-5-9'
- PrincipalSelf =
'S-1-5-10'
- AuthenticatedUsers =
'S-1-5-11'
- RestrictedCode =
'S-1-5-12'
- TerminalServerUsers =
'S-1-5-13'
- LocalSystem =
'S-1-5-18'
- NtLocal =
'S-1-5-19'
- NtNetwork =
'S-1-5-20'
- BuiltinAdministrators =
'S-1-5-32-544'
- BuiltinUsers =
'S-1-5-32-545'
- Guests =
'S-1-5-32-546'
- PowerUsers =
'S-1-5-32-547'
- AccountOperators =
'S-1-5-32-548'
- ServerOperators =
'S-1-5-32-549'
- PrintOperators =
'S-1-5-32-550'
- BackupOperators =
'S-1-5-32-551'
- Replicators =
'S-1-5-32-552'
- AllAppPackages =
'S-1-15-2-1'
- MAXIMUM_SID_STRING_LENGTH =
stackoverflow.com/a/1792930 - 68 bytes, 184 characters in a string
184
Class Method Summary collapse
-
.ads_to_principal(ads_object) ⇒ Object
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.
- .get_length_sid(sid_ptr) ⇒ Object
-
.name_to_principal(name, allow_unresolved = false) ⇒ Object
(also: name_to_sid_object)
Convert an account name, e.g.
-
.name_to_sid(name) ⇒ Object
Convert an account name, e.g.
-
.octet_string_to_principal(bytes) ⇒ Object
(also: octet_string_to_sid_object)
Converts an octet string array of bytes to a SID::Principal object, e.g.
- .octet_string_to_sid_string(sid_bytes) ⇒ Object
-
.sid_ptr_to_string(psid) ⇒ Object
Convert a SID pointer to a SID string, e.g.
-
.sid_to_name(value) ⇒ Object
Convert a SID string, e.g.
-
.string_to_sid_ptr(string_sid, &block) ⇒ Object
Convert a SID string, e.g.
- .unresolved_principal(name, sid_bytes) ⇒ Object private
-
.valid_sid?(string_sid) ⇒ Boolean
Return true if the string is a valid SID, e.g.
Class Method Details
.ads_to_principal(ads_object) ⇒ Object
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
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/puppet/util/windows/sid.rb', line 116 def ads_to_principal(ads_object) if !ads_object || !ads_object.respond_to?(:ole_respond_to?) || !ads_object.ole_respond_to?(:objectSID) || !ads_object.ole_respond_to?(:Name) raise Puppet::Error, "ads_object must be an IAdsUser or IAdsGroup instance" end octet_string_to_principal(ads_object.objectSID) rescue Puppet::Util::Windows::Error => e # if the error is not a lookup / mapping problem, immediately re-raise raise if e.code != ERROR_NONE_MAPPED # if the Name property isn't formatted like a SID, OR if !valid_sid?(ads_object.Name) || # if the objectSID doesn't match the Name property, also raise ((converted = octet_string_to_sid_string(ads_object.objectSID)) != ads_object.Name) raise Puppet::Error.new("ads_object Name: #{ads_object.Name} invalid or does not match objectSID: #{ads_object.objectSID} (#{converted})", e) end unresolved_principal(ads_object.Name, ads_object.objectSID) end |
.get_length_sid(sid_ptr) ⇒ Object
221 222 223 224 225 226 227 228 |
# File 'lib/puppet/util/windows/sid.rb', line 221 def get_length_sid(sid_ptr) # MSDN states IsValidSid should be called on pointer first if !sid_ptr.is_a?(FFI::Pointer) || IsValidSid(sid_ptr) == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error, _("Invalid SID") end GetLengthSid(sid_ptr) end |
.name_to_principal(name, allow_unresolved = false) ⇒ Object Also known as: name_to_sid_object
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
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/puppet/util/windows/sid.rb', line 71 def name_to_principal(name, allow_unresolved = false) # Apparently, we accept a symbol.. name = name.to_s.strip if name # if name is a SID string, convert it to raw bytes for use with lookup_account_sid raw_sid_bytes = nil begin string_to_sid_ptr(name) do |sid_ptr| raw_sid_bytes = sid_ptr.read_array_of_uchar(get_length_sid(sid_ptr)) end rescue => e # Avoid debug logs pollution with valid account names # https://docs.microsoft.com/en-us/windows/win32/api/sddl/nf-sddl-convertstringsidtosidw#return-value Puppet.debug("Could not retrieve raw SID bytes from '#{name}': #{e.}") unless e.code == ERROR_INVALID_SID_STRUCTURE end raw_sid_bytes ? Principal.lookup_account_sid(raw_sid_bytes) : Principal.lookup_account_name(name) rescue => e Puppet.debug(e..to_s) (allow_unresolved && raw_sid_bytes) ? unresolved_principal(name, raw_sid_bytes) : nil end |
.name_to_sid(name) ⇒ Object
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.
59 60 61 62 63 |
# File 'lib/puppet/util/windows/sid.rb', line 59 def name_to_sid(name) sid = name_to_principal(name) sid ? sid.sid : nil end |
.octet_string_to_principal(bytes) ⇒ Object Also known as: octet_string_to_sid_object
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
100 101 102 103 104 105 106 |
# File 'lib/puppet/util/windows/sid.rb', line 100 def octet_string_to_principal(bytes) if !bytes || !bytes.respond_to?('pack') || bytes.empty? raise Puppet::Util::Windows::Error, _("Octet string must be an array of bytes") end Principal.lookup_account_sid(bytes) end |
.octet_string_to_sid_string(sid_bytes) ⇒ Object
231 232 233 234 235 236 237 238 239 240 |
# File 'lib/puppet/util/windows/sid.rb', line 231 def octet_string_to_sid_string(sid_bytes) sid_string = nil FFI::MemoryPointer.new(:byte, sid_bytes.length) do |sid_ptr| sid_ptr.write_array_of_uchar(sid_bytes) sid_string = Puppet::Util::Windows::SID.sid_ptr_to_string(sid_ptr) end sid_string end |
.sid_ptr_to_string(psid) ⇒ Object
Convert a SID pointer to a SID string, e.g. “S-1-5-32-544”.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/puppet/util/windows/sid.rb', line 161 def sid_ptr_to_string(psid) if !psid.is_a?(FFI::Pointer) || IsValidSid(psid) == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error, _("Invalid SID") end sid_string = nil FFI::MemoryPointer.new(:pointer, 1) do |buffer_ptr| if ConvertSidToStringSidW(psid, buffer_ptr) == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error, _("Failed to convert binary SID") end buffer_ptr.read_win32_local_pointer do |wide_string_ptr| if wide_string_ptr.null? raise Puppet::Error, _("ConvertSidToStringSidW failed to allocate buffer for sid") end sid_string = wide_string_ptr.read_arbitrary_wide_string_up_to(MAXIMUM_SID_STRING_LENGTH) end end sid_string end |
.sid_to_name(value) ⇒ Object
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.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/puppet/util/windows/sid.rb', line 141 def sid_to_name(value) sid_bytes = [] begin string_to_sid_ptr(value) do |ptr| sid_bytes = ptr.read_array_of_uchar(get_length_sid(ptr)) end rescue Puppet::Util::Windows::Error => e raise if e.code != ERROR_INVALID_SID_STRUCTURE end Principal.lookup_account_sid(sid_bytes).domain_account rescue nil end |
.string_to_sid_ptr(string_sid, &block) ⇒ Object
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.
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/puppet/util/windows/sid.rb', line 189 def string_to_sid_ptr(string_sid, &block) FFI::MemoryPointer.from_string_to_wide_string(string_sid) do |lpcwstr| FFI::MemoryPointer.new(:pointer, 1) do |sid_ptr_ptr| if ConvertStringSidToSidW(lpcwstr, sid_ptr_ptr) == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error, _("Failed to convert string SID: %{string_sid}") % { string_sid: string_sid } end sid_ptr_ptr.read_win32_local_pointer do |sid_ptr| yield sid_ptr end end end # yielded sid_ptr has already had LocalFree called, nothing to return nil end |
.unresolved_principal(name, sid_bytes) ⇒ 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.
244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/puppet/util/windows/sid.rb', line 244 def self.unresolved_principal(name, sid_bytes) Principal.new( name, # account sid_bytes, # sid_bytes name, # sid string nil, # domain # https://msdn.microsoft.com/en-us/library/cc245534.aspx?f=255&MSPPError=-2147217396 # Indicates that the type of object could not be determined. For example, no object with that SID exists. :SidTypeUnknown ) end |
.valid_sid?(string_sid) ⇒ Boolean
Return true if the string is a valid SID, e.g. “S-1-5-32-544”, false otherwise.
208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/puppet/util/windows/sid.rb', line 208 def valid_sid?(string_sid) valid = false begin string_to_sid_ptr(string_sid) { |ptr| valid = !ptr.nil? && !ptr.null? } rescue Puppet::Util::Windows::Error => e raise if e.code != ERROR_INVALID_SID_STRUCTURE end valid end |