summaryrefslogtreecommitdiff
path: root/lib/chef
diff options
context:
space:
mode:
authorsersut <serdar@opscode.com>2014-07-09 16:05:27 -0700
committersersut <serdar@opscode.com>2014-07-14 13:18:31 -0700
commit04612158ac256ce46faad599e141ff7d1161fd66 (patch)
tree5d6ff018c0173c2ec0282bf9e68357964a06e578 /lib/chef
parent3ec42a522a5b40d1ef217f23831b7417bda65761 (diff)
downloadchef-04612158ac256ce46faad599e141ff7d1161fd66.tar.gz
Automatically find out the sid for Administrators so that the specs can run on boxes for which the administrators account is renamed.
Diffstat (limited to 'lib/chef')
-rw-r--r--lib/chef/win32/api/net.rb90
-rw-r--r--lib/chef/win32/security/sid.rb56
-rw-r--r--lib/chef/win32/unicode.rb14
3 files changed, 156 insertions, 4 deletions
diff --git a/lib/chef/win32/api/net.rb b/lib/chef/win32/api/net.rb
new file mode 100644
index 0000000000..cb028020cf
--- /dev/null
+++ b/lib/chef/win32/api/net.rb
@@ -0,0 +1,90 @@
+#
+# Author:: Serdar Sutay (<serdar@getchef.com>)
+# Copyright:: Copyright 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/win32/api'
+
+class Chef
+ module ReservedNames::Win32
+ module API
+ module Net
+ extend Chef::ReservedNames::Win32::API
+
+ FILTER_TEMP_DUPLICATE_ACCOUNT = 0x0001
+ FILTER_NORMAL_ACCOUNT = 0x0002
+ FILTER_INTERDOMAIN_TRUST_ACCOUNT = 0x0008
+ FILTER_WORKSTATION_TRUST_ACCOUNT = 0x0010
+ FILTER_SERVER_TRUST_ACCOUNT = 0x0020
+
+ MAX_PREFERRED_LENGTH = 0xFFFF
+
+ NERR_Success = 0
+
+ ffi_lib "netapi32"
+
+ class USER_INFO_3 < FFI::Struct
+ layout :usri3_name, :LPWSTR,
+ :usri3_password, :LPWSTR,
+ :usri3_password_age, :DWORD,
+ :usri3_priv, :DWORD,
+ :usri3_home_dir, :LPWSTR,
+ :usri3_comment, :LPWSTR,
+ :usri3_flags, :DWORD,
+ :usri3_script_path, :LPWSTR,
+ :usri3_auth_flags, :DWORD,
+ :usri3_full_name, :LPWSTR,
+ :usri3_usr_comment, :LPWSTR,
+ :usri3_parms, :LPWSTR,
+ :usri3_workstations, :LPWSTR,
+ :usri3_last_logon, :DWORD,
+ :usri3_last_logoff, :DWORD,
+ :usri3_acct_expires, :DWORD,
+ :usri3_max_storage, :DWORD,
+ :usri3_units_per_week, :DWORD,
+ :usri3_logon_hours, :PBYTE,
+ :usri3_bad_pw_count, :DWORD,
+ :usri3_num_logons, :DWORD,
+ :usri3_logon_server, :LPWSTR,
+ :usri3_country_code, :DWORD,
+ :usri3_code_page, :DWORD,
+ :usri3_user_id, :DWORD,
+ :usri3_primary_group_id, :DWORD,
+ :usri3_profile, :LPWSTR,
+ :usri3_home_dir_drive, :LPWSTR,
+ :usri3_password_expired, :DWORD
+ end
+
+# NET_API_STATUS NetUserEnum(
+# _In_ LPCWSTR servername,
+# _In_ DWORD level,
+# _In_ DWORD filter,
+# _Out_ LPBYTE *bufptr,
+# _In_ DWORD prefmaxlen,
+# _Out_ LPDWORD entriesread,
+# _Out_ LPDWORD totalentries,
+# _Inout_ LPDWORD resume_handle
+# );
+ safe_attach_function :NetUserEnum, [ :LPCWSTR, :DWORD, :DWORD, :LPBYTE, :DWORD, :LPDWORD, :LPDWORD, :LPDWORD ], :DWORD
+
+# NET_API_STATUS NetApiBufferFree(
+# _In_ LPVOID Buffer
+# );
+ safe_attach_function :NetApiBufferFree, [ :LPVOID ], :DWORD
+ end
+ end
+ end
+end
diff --git a/lib/chef/win32/security/sid.rb b/lib/chef/win32/security/sid.rb
index e1b20224bb..8e9407dc80 100644
--- a/lib/chef/win32/security/sid.rb
+++ b/lib/chef/win32/security/sid.rb
@@ -17,11 +17,22 @@
#
require 'chef/win32/security'
+require 'chef/win32/api/net'
+require 'chef/win32/api/error'
+
+require 'wmi-lite/wmi'
class Chef
module ReservedNames::Win32
class Security
class SID
+ include Chef::ReservedNames::Win32::API::Net
+ include Chef::ReservedNames::Win32::API::Error
+
+ class << self
+ include Chef::ReservedNames::Win32::API::Net
+ include Chef::ReservedNames::Win32::API::Error
+ end
def initialize(pointer, owner = nil)
@pointer = pointer
@@ -178,13 +189,11 @@ class Chef
SID.from_string_sid('S-1-5-32-544')
end
- # Machine-specific, well-known SIDs
- # TODO: don't use strings, dummy
def self.None
SID.from_account("#{::ENV['COMPUTERNAME']}\\None")
end
def self.Administrator
- SID.from_account("#{::ENV['COMPUTERNAME']}\\Administrator")
+ SID.from_account("#{::ENV['COMPUTERNAME']}\\#{SID.admin_account_name}")
end
def self.Guest
SID.from_account("#{::ENV['COMPUTERNAME']}\\Guest")
@@ -193,6 +202,47 @@ class Chef
def self.current_user
SID.from_account("#{::ENV['USERDOMAIN']}\\#{::ENV['USERNAME']}")
end
+
+ def self.admin_account_name
+ @admin_account_name ||= begin
+ admin_account_name = nil
+
+ # Call NetUserEnum to enumerate the users without hitting network
+ # http://msdn.microsoft.com/en-us/library/windows/desktop/aa370652(v=vs.85).aspx
+ servername = nil # We are querying the local server
+ level = 3 # We want USER_INFO_3 structure which contains the SID
+ filter = FILTER_NORMAL_ACCOUNT # Only query the user accounts
+ bufptr = FFI::MemoryPointer.new(:pointer) # Buffer which will receive the data
+ prefmaxlen = MAX_PREFERRED_LENGTH # Let the system allocate the needed amount of memory
+ entriesread = FFI::Buffer.new(:long).write_long(0)
+ totalentries = FFI::Buffer.new(:long).write_long(0)
+ resume_handle = FFI::Buffer.new(:long).write_long(0)
+
+ status = ERROR_MORE_DATA
+
+ while(status == ERROR_MORE_DATA) do
+ status = NetUserEnum(servername, level, filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle)
+
+ if (status == NERR_Success || status == ERROR_MORE_DATA)
+ entriesread.read_long.times.collect do |i|
+ user_info = USER_INFO_3.new(bufptr.read_pointer + i * USER_INFO_3.size)
+ # Check if the account is the Administrator account
+ # RID for the Administrator account is always 500 and it's privilage is set to USER_PRIV_ADMIN
+ if user_info[:usri3_user_id] == 500 && user_info[:usri3_priv] == 2 # USER_PRIV_ADMIN (2) - Administrator
+ admin_account_name = user_info[:usri3_name].read_wstring
+ break
+ end
+ end
+
+ # Free the memory allocated by the system
+ NetApiBufferFree(bufptr.read_pointer)
+ end
+ end
+
+ raise "Can not determine the administrator account name." if admin_account_name.nil?
+ admin_account_name
+ end
+ end
end
end
end
diff --git a/lib/chef/win32/unicode.rb b/lib/chef/win32/unicode.rb
index 1002a4d58f..e7399d5255 100644
--- a/lib/chef/win32/unicode.rb
+++ b/lib/chef/win32/unicode.rb
@@ -30,7 +30,19 @@ end
module FFI
class Pointer
- def read_wstring(num_wchars)
+ def read_wstring(num_wchars = nil)
+ if num_wchars.nil?
+ # Find the length of the string
+ length = 0
+ last_char = nil
+ while last_char != "\000\000" do
+ length += 1
+ last_char = self.get_bytes(0,length * 2)[-2..-1]
+ end
+
+ num_wchars = length
+ end
+
Chef::ReservedNames::Win32::Unicode.wide_to_utf8(self.get_bytes(0, num_wchars*2))
end
end