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

Public Instance Methods

==(compare) click to toggle source

added for backward compatibility

   # File lib/puppet/util/windows/principal.rb
30 def ==(compare)
31   compare.is_a?(Puppet::Util::Windows::SID::Principal) &&
32     @sid_bytes == compare.sid_bytes
33 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
37 def to_s
38   @domain_account
39 end