class Puppet::Util::Windows::SID::Principal

Constants

ERROR_INSUFFICIENT_BUFFER
ERROR_INVALID_PARAMETER
MAXIMUM_SID_BYTE_LENGTH

8 + max sub identifiers (15) * 4

SID_NAME_USE

msdn.microsoft.com/en-us/library/windows/desktop/aa379601(v=vs.85).aspx

Attributes

account[R]
account_type[R]
domain[R]
domain_account[R]
sid[R]
sid_bytes[R]

Public Class Methods

lookup_account_name(system_name = nil, sanitize = true, account_name) click to toggle source
   # File lib/puppet/util/windows/principal.rb
48 def self.lookup_account_name(system_name = nil, sanitize = true, account_name)
49   account_name = sanitize_account_name(account_name) if sanitize
50   system_name_ptr = FFI::Pointer::NULL
51   begin
52     if system_name
53       system_name_wide = Puppet::Util::Windows::String.wide_string(system_name)
54       system_name_ptr = FFI::MemoryPointer.from_wide_string(system_name_wide)
55     end
56 
57     FFI::MemoryPointer.from_string_to_wide_string(account_name) do |account_name_ptr|
58       FFI::MemoryPointer.new(:byte, MAXIMUM_SID_BYTE_LENGTH) do |sid_ptr|
59         FFI::MemoryPointer.new(:dword, 1) do |sid_length_ptr|
60           FFI::MemoryPointer.new(:dword, 1) do |domain_length_ptr|
61             FFI::MemoryPointer.new(:uint32, 1) do |name_use_enum_ptr|
62 
63             sid_length_ptr.write_dword(MAXIMUM_SID_BYTE_LENGTH)
64             success = LookupAccountNameW(system_name_ptr, account_name_ptr, sid_ptr, sid_length_ptr,
65               FFI::Pointer::NULL, domain_length_ptr, name_use_enum_ptr)
66             last_error = FFI.errno
67 
68             if (success == FFI::WIN32_FALSE && last_error != ERROR_INSUFFICIENT_BUFFER)
69               raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountNameW with account: %{account_name}') % { account_name: account_name}, last_error)
70             end
71 
72             FFI::MemoryPointer.new(:lpwstr, domain_length_ptr.read_dword) do |domain_ptr|
73               if LookupAccountNameW(system_name_ptr, account_name_ptr,
74                   sid_ptr, sid_length_ptr,
75                   domain_ptr, domain_length_ptr, name_use_enum_ptr) == FFI::WIN32_FALSE
76               raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountNameW with account: %{account_name}') % { account_name: account_name} )
77               end
78 
79               # with a SID returned, loop back through lookup_account_sid to retrieve official name
80               # necessary when accounts like . or '' are passed in
81               return lookup_account_sid(
82                 system_name,
83                 sid_ptr.read_bytes(sid_length_ptr.read_dword).unpack('C*'))
84               end
85             end
86           end
87         end
88       end
89     end
90   ensure
91     system_name_ptr.free if system_name_ptr != FFI::Pointer::NULL
92   end
93 end
lookup_account_sid(system_name = nil, sid_bytes) click to toggle source
    # File lib/puppet/util/windows/principal.rb
 95 def self.lookup_account_sid(system_name = nil, sid_bytes)
 96   system_name_ptr = FFI::Pointer::NULL
 97   if (sid_bytes.nil? || (!sid_bytes.is_a? Array) || (sid_bytes.length == 0))
 98     #TRANSLATORS `lookup_account_sid` is a variable name and should not be translated
 99     raise Puppet::Util::Windows::Error.new(_('Byte array for lookup_account_sid must not be nil and must be at least 1 byte long'))
100   end
101 
102   begin
103     if system_name
104       system_name_wide = Puppet::Util::Windows::String.wide_string(system_name)
105       system_name_ptr = FFI::MemoryPointer.from_wide_string(system_name_wide)
106     end
107 
108     FFI::MemoryPointer.new(:byte, sid_bytes.length) do |sid_ptr|
109       FFI::MemoryPointer.new(:dword, 1) do |name_length_ptr|
110         FFI::MemoryPointer.new(:dword, 1) do |domain_length_ptr|
111           FFI::MemoryPointer.new(:uint32, 1) do |name_use_enum_ptr|
112 
113             sid_ptr.write_array_of_uchar(sid_bytes)
114 
115             if Puppet::Util::Windows::SID.IsValidSid(sid_ptr) == FFI::WIN32_FALSE
116               raise Puppet::Util::Windows::Error.new(_('Byte array for lookup_account_sid is invalid: %{sid_bytes}') % { sid_bytes: sid_bytes }, ERROR_INVALID_PARAMETER)
117             end
118 
119             success = LookupAccountSidW(system_name_ptr, sid_ptr, FFI::Pointer::NULL, name_length_ptr,
120               FFI::Pointer::NULL, domain_length_ptr, name_use_enum_ptr)
121             last_error = FFI.errno
122 
123             if (success == FFI::WIN32_FALSE && last_error != ERROR_INSUFFICIENT_BUFFER)
124               raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountSidW with bytes: %{sid_bytes}') % { sid_bytes: sid_bytes}, last_error)
125             end
126 
127             FFI::MemoryPointer.new(:lpwstr, name_length_ptr.read_dword) do |name_ptr|
128               FFI::MemoryPointer.new(:lpwstr, domain_length_ptr.read_dword) do |domain_ptr|
129                 if LookupAccountSidW(system_name_ptr, sid_ptr, name_ptr, name_length_ptr,
130                     domain_ptr, domain_length_ptr, name_use_enum_ptr) == FFI::WIN32_FALSE
131                  raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountSidW with bytes: %{sid_bytes}') % { sid_bytes: sid_bytes} )
132                 end
133 
134                 return new(
135                   name_ptr.read_wide_string(name_length_ptr.read_dword),
136                   sid_bytes,
137                   Puppet::Util::Windows::SID.sid_ptr_to_string(sid_ptr),
138                   domain_ptr.read_wide_string(domain_length_ptr.read_dword),
139                   SID_NAME_USE[name_use_enum_ptr.read_uint32])
140               end
141             end
142           end
143         end
144       end
145     end
146   ensure
147     system_name_ptr.free if system_name_ptr != FFI::Pointer::NULL
148   end
149 end
new(account, sid_bytes, sid, domain, account_type) click to toggle source
   # File lib/puppet/util/windows/principal.rb
 9 def initialize(account, sid_bytes, sid, domain, account_type)
10   # This is only ever called from lookup_account_sid which has already
11   # removed the potential for passing in an account like host\user
12   @account = account
13   @sid_bytes = sid_bytes
14   @sid = sid
15   @domain = domain
16   @account_type = account_type
17   # When domain is available and it is a Domain principal, use domain only
18   #   otherwise if domain is available then combine it with parsed account
19   #   otherwise when the domain is not available, use the account value directly
20   # WinNT naming standard https://msdn.microsoft.com/en-us/library/windows/desktop/aa746534(v=vs.85).aspx
21   if (domain && !domain.empty? && @account_type == :SidTypeDomain)
22     @domain_account = @domain
23   elsif (domain && !domain.empty?)
24     @domain_account =  "#{domain}\\#{@account}"
25   else
26     @domain_account = account
27   end
28 end

Private Class Methods

sanitize_account_name(account_name) click to toggle source

Sanitize the given account name for lookup to avoid known issues

    # File lib/puppet/util/windows/principal.rb
152 def self.sanitize_account_name(account_name)
153   return account_name unless account_name.start_with?('APPLICATION PACKAGE AUTHORITY\\')
154   account_name.split('\\').last
155 end

Public Instance Methods

==(compare) click to toggle source

added for backward compatibility

   # File lib/puppet/util/windows/principal.rb
31 def ==(compare)
32   compare.is_a?(Puppet::Util::Windows::SID::Principal) &&
33     @sid_bytes == compare.sid_bytes
34 end
to_s() click to toggle source

returns authority qualified account name prefer to compare Principal instances with == operator or by sid

   # File lib/puppet/util/windows/principal.rb
38 def to_s
39   @domain_account
40 end