diff options
Diffstat (limited to 'lib/chef/win32')
-rw-r--r-- | lib/chef/win32/api.rb | 1 | ||||
-rw-r--r-- | lib/chef/win32/api/security.rb | 26 | ||||
-rw-r--r-- | lib/chef/win32/file.rb | 21 | ||||
-rw-r--r-- | lib/chef/win32/security.rb | 46 | ||||
-rw-r--r-- | lib/chef/win32/security/token.rb | 8 | ||||
-rw-r--r-- | lib/chef/win32/version.rb | 4 |
6 files changed, 102 insertions, 4 deletions
diff --git a/lib/chef/win32/api.rb b/lib/chef/win32/api.rb index 0330810b3b..8b81947c9b 100644 --- a/lib/chef/win32/api.rb +++ b/lib/chef/win32/api.rb @@ -159,6 +159,7 @@ class Chef host.typedef :pointer, :PDWORD32 # Pointer to a DWORD32. host.typedef :pointer, :PDWORD64 # Pointer to a DWORD64. host.typedef :pointer, :PFLOAT # Pointer to a FLOAT. + host.typedef :pointer, :PGENERICMAPPING #Pointer to GENERIC_MAPPING host.typedef :pointer, :PHALF_PTR # Pointer to a HALF_PTR. host.typedef :pointer, :PHANDLE # Pointer to a HANDLE. host.typedef :pointer, :PHKEY # Pointer to an HKEY. diff --git a/lib/chef/win32/api/security.rb b/lib/chef/win32/api/security.rb index 7ca2d70c8e..229f2ace10 100644 --- a/lib/chef/win32/api/security.rb +++ b/lib/chef/win32/api/security.rb @@ -270,6 +270,15 @@ class Chef :MaxTokenInfoClass ] + # https://msdn.microsoft.com/en-us/library/windows/desktop/aa379572%28v=vs.85%29.aspx + SECURITY_IMPERSONATION_LEVEL = enum :SECURITY_IMPERSONATION_LEVEL, [ + :SecurityAnonymous, + :SecurityIdentification, + :SecurityImpersonation, + :SecurityDelegation + ] + + # SECURITY_DESCRIPTOR is an opaque structure whose contents can vary. Pass the # pointer around and free it with LocalFree. # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379561(v=vs.85).aspx @@ -320,6 +329,19 @@ class Chef :Attributes, :DWORD end + class GENERIC_MAPPING < FFI::Struct + layout :GenericRead, :DWORD, + :GenericWrite, :DWORD, + :GenericExecute, :DWORD, + :GenericAll, :DWORD + end + + class PRIVILEGE_SET < FFI::Struct + layout :PrivilegeCount, :DWORD, + :Control, :DWORD, + :Privilege, [LUID_AND_ATTRIBUTES, 1] + end + class TOKEN_PRIVILEGES < FFI::Struct layout :PrivilegeCount, :DWORD, :Privileges, LUID_AND_ATTRIBUTES @@ -339,6 +361,7 @@ class Chef ffi_lib "advapi32" + safe_attach_function :AccessCheck, [:pointer, :HANDLE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer], :BOOL safe_attach_function :AddAce, [ :pointer, :DWORD, :DWORD, :LPVOID, :DWORD ], :BOOL safe_attach_function :AddAccessAllowedAce, [ :pointer, :DWORD, :DWORD, :pointer ], :BOOL safe_attach_function :AddAccessAllowedAceEx, [ :pointer, :DWORD, :DWORD, :DWORD, :pointer ], :BOOL @@ -348,9 +371,11 @@ class Chef safe_attach_function :ConvertSidToStringSidA, [ :pointer, :pointer ], :BOOL safe_attach_function :ConvertStringSidToSidW, [ :pointer, :pointer ], :BOOL safe_attach_function :DeleteAce, [ :pointer, :DWORD ], :BOOL + safe_attach_function :DuplicateToken, [:HANDLE, :SECURITY_IMPERSONATION_LEVEL, :PHANDLE], :BOOL safe_attach_function :EqualSid, [ :pointer, :pointer ], :BOOL safe_attach_function :FreeSid, [ :pointer ], :pointer safe_attach_function :GetAce, [ :pointer, :DWORD, :pointer ], :BOOL + safe_attach_function :GetFileSecurityW, [:LPCWSTR, :DWORD, :pointer, :DWORD, :pointer], :BOOL safe_attach_function :GetLengthSid, [ :pointer ], :DWORD safe_attach_function :GetNamedSecurityInfoW, [ :LPWSTR, :SE_OBJECT_TYPE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer ], :DWORD safe_attach_function :GetSecurityDescriptorControl, [ :pointer, :PWORD, :LPDWORD], :BOOL @@ -369,6 +394,7 @@ class Chef safe_attach_function :LookupPrivilegeDisplayNameW, [ :LPCWSTR, :LPCWSTR, :LPWSTR, :LPDWORD, :LPDWORD ], :BOOL safe_attach_function :LookupPrivilegeValueW, [ :LPCWSTR, :LPCWSTR, :PLUID ], :BOOL safe_attach_function :MakeAbsoluteSD, [ :pointer, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD], :BOOL + safe_attach_function :MapGenericMask, [ :PDWORD, :PGENERICMAPPING ], :void safe_attach_function :OpenProcessToken, [ :HANDLE, :DWORD, :PHANDLE ], :BOOL safe_attach_function :QuerySecurityAccessMask, [ :DWORD, :LPDWORD ], :void safe_attach_function :SetFileSecurityW, [ :LPWSTR, :DWORD, :pointer ], :BOOL diff --git a/lib/chef/win32/file.rb b/lib/chef/win32/file.rb index d489c9ce8a..e6640caa3c 100644 --- a/lib/chef/win32/file.rb +++ b/lib/chef/win32/file.rb @@ -155,6 +155,27 @@ class Chef end end + def self.file_access_check(path, desired_access) + security_descriptor = Chef::ReservedNames::Win32::Security.get_file_security(path) + token_rights = Chef::ReservedNames::Win32::Security::TOKEN_IMPERSONATE | + Chef::ReservedNames::Win32::Security::TOKEN_QUERY | + Chef::ReservedNames::Win32::Security::TOKEN_DUPLICATE | + Chef::ReservedNames::Win32::Security::STANDARD_RIGHTS_READ + token = Chef::ReservedNames::Win32::Security.open_process_token( + Chef::ReservedNames::Win32::Process.get_current_process, + token_rights) + duplicate_token = token.duplicate_token(:SecurityImpersonation) + + mapping = Chef::ReservedNames::Win32::Security::GENERIC_MAPPING.new + mapping[:GenericRead] = Chef::ReservedNames::Win32::Security::FILE_GENERIC_READ + mapping[:GenericWrite] = Chef::ReservedNames::Win32::Security::FILE_GENERIC_WRITE + mapping[:GenericExecute] = Chef::ReservedNames::Win32::Security::FILE_GENERIC_EXECUTE + mapping[:GenericAll] = Chef::ReservedNames::Win32::Security::FILE_ALL_ACCESS + + Chef::ReservedNames::Win32::Security.access_check(security_descriptor, duplicate_token, + desired_access, mapping) + end + # ::File compat class << self alias :stat :info diff --git a/lib/chef/win32/security.rb b/lib/chef/win32/security.rb index 48ca78647f..3902d8caaf 100644 --- a/lib/chef/win32/security.rb +++ b/lib/chef/win32/security.rb @@ -32,6 +32,34 @@ class Chef extend Chef::ReservedNames::Win32::API::Security extend Chef::ReservedNames::Win32::API::Macros + def self.access_check(security_descriptor, token, desired_access, generic_mapping) + token_handle = token.handle.handle + security_descriptor_ptr = security_descriptor.pointer + + rights_ptr = FFI::MemoryPointer.new(:ulong) + rights_ptr.write_ulong(desired_access) + + # This function takes care of calling MapGenericMask, so you don't have to + MapGenericMask(rights_ptr, generic_mapping) + + result_ptr = FFI::MemoryPointer.new(:ulong) + + # Because optional actually means required + privileges = PRIVILEGE_SET.new + privileges[:PrivilegeCount] = 0 + privileges_length_ptr = FFI::MemoryPointer.new(:ulong) + privileges_length_ptr.write_ulong(privileges.size) + + granted_access_ptr = FFI::MemoryPointer.new(:ulong) + + unless AccessCheck(security_descriptor_ptr, token_handle, rights_ptr.read_ulong, + generic_mapping, privileges, privileges_length_ptr, granted_access_ptr, + result_ptr) + Chef::ReservedNames::Win32::Error.raise! + end + result_ptr.read_ulong == 1 + end + def self.add_ace(acl, ace, insert_position = MAXDWORD, revision = ACL_REVISION) acl = acl.pointer if acl.respond_to?(:pointer) ace = ace.pointer if ace.respond_to?(:pointer) @@ -148,6 +176,24 @@ class Chef GetLengthSid(sid) end + def self.get_file_security(path, info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION) + size_ptr = FFI::MemoryPointer.new(:ulong) + + success = GetFileSecurityW(path.to_wstring, info, nil, 0, size_ptr) + + if !success && FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER + Chef::ReservedNames::Win32::Error.raise! + end + + security_descriptor_ptr = FFI::MemoryPointer.new(size_ptr.read_ulong) + unless GetFileSecurityW(path.to_wstring, info, security_descriptor_ptr, size_ptr.read_ulong, size_ptr) + Chef::ReservedNames::Win32::Error.raise! + end + + SecurityDescriptor.new(security_descriptor_ptr) + end + + def self.get_named_security_info(path, type = :SE_FILE_OBJECT, info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION) security_descriptor = FFI::MemoryPointer.new :pointer hr = GetNamedSecurityInfoW(path.to_wstring, type, info, nil, nil, nil, nil, security_descriptor) diff --git a/lib/chef/win32/security/token.rb b/lib/chef/win32/security/token.rb index ded4fc080e..9e494a73b9 100644 --- a/lib/chef/win32/security/token.rb +++ b/lib/chef/win32/security/token.rb @@ -58,6 +58,14 @@ class Chef Chef::ReservedNames::Win32::Security::adjust_token_privileges(self, privileges_struct) end end + + def duplicate_token(security_impersonation_level) + duplicate_token_handle = FFI::Buffer.new(:ulong) + unless Chef::ReservedNames::Win32::API::Security.DuplicateToken(handle.handle, security_impersonation_level, duplicate_token_handle) + raise Chef::ReservedNames::Win32::Error.raise! + end + Token.new(Handle.new(duplicate_token_handle.read_ulong)) + end end end end diff --git a/lib/chef/win32/version.rb b/lib/chef/win32/version.rb index d16bd8c12f..6a5bd35a26 100644 --- a/lib/chef/win32/version.rb +++ b/lib/chef/win32/version.rb @@ -126,14 +126,10 @@ class Chef # https://github.com/ruby/ruby/commit/588504b20f5cc880ad51827b93e571e32446e5db # https://github.com/ruby/ruby/commit/27ed294c7134c0de582007af3c915a635a6506cd - WIN32OLE.ole_initialize - wmi = WmiLite::Wmi.new os_info = wmi.first_of('Win32_OperatingSystem') os_version = os_info['version'] - WIN32OLE.ole_uninitialize - # The operating system version is a string in the following form # that can be split into components based on the '.' delimiter: # MajorVersionNumber.MinorVersionNumber.BuildNumber |