diff options
author | Matt Wrock <matt@mattwrock.com> | 2015-12-29 10:31:41 -0800 |
---|---|---|
committer | Matt Wrock <matt@mattwrock.com> | 2015-12-29 10:31:41 -0800 |
commit | 7f69ad99a2446e9c70112aa531f68a971a52758f (patch) | |
tree | 918bc63c8ffb8f1354b25378155c478b6fdad2ac /lib/chef/win32 | |
parent | b027f4b9cebda8314118a0839f93d812e1b6fcfa (diff) | |
download | chef-7f69ad99a2446e9c70112aa531f68a971a52758f.tar.gz |
fixes #3521 correcting format of user name passed to policy apis and does not clobber existing service rights of other users
Diffstat (limited to 'lib/chef/win32')
-rw-r--r-- | lib/chef/win32/api.rb | 7 | ||||
-rw-r--r-- | lib/chef/win32/api/security.rb | 38 | ||||
-rw-r--r-- | lib/chef/win32/error.rb | 3 | ||||
-rw-r--r-- | lib/chef/win32/security.rb | 63 |
4 files changed, 108 insertions, 3 deletions
diff --git a/lib/chef/win32/api.rb b/lib/chef/win32/api.rb index 4786222bd4..de3381c5ba 100644 --- a/lib/chef/win32/api.rb +++ b/lib/chef/win32/api.rb @@ -147,6 +147,8 @@ class Chef host.typedef :long, :LRESULT # Signed result of message processing. WinDef.h: host.typedef LONG_PTR LRESULT; host.typedef :pointer, :LPWIN32_FIND_DATA # Pointer to WIN32_FIND_DATA struct host.typedef :pointer, :LPBY_HANDLE_FILE_INFORMATION # Point to a BY_HANDLE_FILE_INFORMATION struct + host.typedef :pointer, :LSA_HANDLE # A handle to a Policy object + host.typedef :ulong, :NTSTATUS # An NTSTATUS code returned by an LSA function call. host.typedef :pointer, :PBOOL # Pointer to a BOOL. host.typedef :pointer, :PBOOLEAN # Pointer to a BOOL. host.typedef :pointer, :PBYTE # Pointer to a BYTE. @@ -174,12 +176,16 @@ class Chef host.typedef :pointer, :PLONG_PTR # Pointer to a LONG_PTR. host.typedef :pointer, :PLONG32 # Pointer to a LONG32. host.typedef :pointer, :PLONG64 # Pointer to a LONG64. + host.typedef :pointer, :PLSA_HANDLE # Pointer to an LSA_HANDLE + host.typedef :pointer, :PLSA_OBJECT_ATTRIBUTES # Pointer to an LSA_OBJECT_ATTRIBUTES + host.typedef :pointer, :PLSA_UNICODE_STRING # Pointer to LSA_UNICODE_STRING host.typedef :pointer, :PLUID # Pointer to a LUID. host.typedef :pointer, :POINTER_32 # 32-bit pointer. On a 32-bit system, this is a native pointer. On a 64-bit system, this is a truncated 64-bit pointer. host.typedef :pointer, :POINTER_64 # 64-bit pointer. On a 64-bit system, this is a native pointer. On a 32-bit system, this is a sign-extended 32-bit pointer. host.typedef :pointer, :POINTER_SIGNED # A signed pointer. host.typedef :pointer, :POINTER_UNSIGNED # An unsigned pointer. host.typedef :pointer, :PSHORT # Pointer to a SHORT. + host.typedef :pointer, :PSID # Pointer to an account SID host.typedef :pointer, :PSIZE_T # Pointer to a SIZE_T. host.typedef :pointer, :PSSIZE_T # Pointer to a SSIZE_T. host.typedef :pointer, :PSTR # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts. @@ -188,7 +194,6 @@ class Chef host.typedef :pointer, :PCRYPTPROTECT_PROMPTSTRUCT # Pointer to a CRYPTOPROTECT_PROMPTSTRUCT. host.typedef :pointer, :PDATA_BLOB # Pointer to a DATA_BLOB. host.typedef :pointer, :PTSTR # A PWSTR if UNICODE is defined, a PSTR otherwise. - host.typedef :pointer, :PSID host.typedef :pointer, :PUCHAR # Pointer to a UCHAR. host.typedef :pointer, :PUHALF_PTR # Pointer to a UHALF_PTR. host.typedef :pointer, :PUINT # Pointer to a UINT. diff --git a/lib/chef/win32/api/security.rb b/lib/chef/win32/api/security.rb index 4c352a3554..4353c488f8 100644 --- a/lib/chef/win32/api/security.rb +++ b/lib/chef/win32/api/security.rb @@ -207,6 +207,21 @@ class Chef LOGON32_PROVIDER_WINNT40 = 2; LOGON32_PROVIDER_WINNT50 = 3; + # LSA access policy + POLICY_VIEW_LOCAL_INFORMATION = 0x00000001 + POLICY_VIEW_AUDIT_INFORMATION = 0x00000002 + POLICY_GET_PRIVATE_INFORMATION = 0x00000004 + POLICY_TRUST_ADMIN = 0x00000008 + POLICY_CREATE_ACCOUNT = 0x00000010 + POLICY_CREATE_SECRET = 0x00000020 + POLICY_CREATE_PRIVILEGE = 0x00000040 + POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080 + POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100 + POLICY_AUDIT_LOG_ADMIN = 0x00000200 + POLICY_SERVER_ADMIN = 0x00000400 + POLICY_LOOKUP_NAMES = 0x00000800 + POLICY_NOTIFICATION = 0x00001000 + ############################################### # Win32 API Bindings ############################################### @@ -381,6 +396,23 @@ class Chef end end + # https://msdn.microsoft.com/en-us/library/windows/desktop/ms721829(v=vs.85).aspx + class LSA_OBJECT_ATTRIBUTES < FFI::Struct + layout :Length, :ULONG, + :RootDirectory, :HANDLE, + :ObjectName, :pointer, + :Attributes, :ULONG, + :SecurityDescriptor, :PVOID, + :SecurityQualityOfService, :PVOID + end + + # https://msdn.microsoft.com/en-us/library/windows/desktop/ms721841(v=vs.85).aspx + class LSA_UNICODE_STRING < FFI::Struct + layout :Length, :USHORT, + :MaximumLength, :USHORT, + :Buffer, :PWSTR + end + ffi_lib "advapi32" safe_attach_function :AccessCheck, [:pointer, :HANDLE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer], :BOOL @@ -415,6 +447,12 @@ class Chef safe_attach_function :LookupPrivilegeNameW, [ :LPCWSTR, :PLUID, :LPWSTR, :LPDWORD ], :BOOL safe_attach_function :LookupPrivilegeDisplayNameW, [ :LPCWSTR, :LPCWSTR, :LPWSTR, :LPDWORD, :LPDWORD ], :BOOL safe_attach_function :LookupPrivilegeValueW, [ :LPCWSTR, :LPCWSTR, :PLUID ], :BOOL + safe_attach_function :LsaAddAccountRights, [ :pointer, :pointer, :pointer, :ULONG ], :NTSTATUS + safe_attach_function :LsaClose, [ :LSA_HANDLE ], :NTSTATUS + safe_attach_function :LsaEnumerateAccountRights, [ :LSA_HANDLE, :PSID, :PLSA_UNICODE_STRING, :PULONG ], :NTSTATUS + safe_attach_function :LsaFreeMemory, [ :PVOID ], :NTSTATUS + safe_attach_function :LsaNtStatusToWinError, [ :NTSTATUS ], :ULONG + safe_attach_function :LsaOpenPolicy, [ :PLSA_UNICODE_STRING, :PLSA_OBJECT_ATTRIBUTES, :DWORD, :PLSA_HANDLE ], :NTSTATUS 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 diff --git a/lib/chef/win32/error.rb b/lib/chef/win32/error.rb index 2175608eeb..c638773d2a 100644 --- a/lib/chef/win32/error.rb +++ b/lib/chef/win32/error.rb @@ -57,8 +57,7 @@ class Chef # nil::: always returns nil when it does not raise # === Raises # Chef::Exceptions::Win32APIError::: - def self.raise!(message = nil) - code = get_last_error + def self.raise!(message = nil, code = get_last_error) msg = format_message(code).strip formatted_message = "" formatted_message << message if message diff --git a/lib/chef/win32/security.rb b/lib/chef/win32/security.rb index bc80517d80..38694c9fec 100644 --- a/lib/chef/win32/security.rb +++ b/lib/chef/win32/security.rb @@ -104,6 +104,22 @@ class Chef end end + def self.add_account_right(name, privilege) + privilege_pointer = FFI::MemoryPointer.new LSA_UNICODE_STRING, 1 + privilege_lsa_string = LSA_UNICODE_STRING.new(privilege_pointer) + privilege_lsa_string[:Buffer] = FFI::MemoryPointer.from_string(privilege.to_wstring) + privilege_lsa_string[:Length] = privilege.length * 2 + privilege_lsa_string[:MaximumLength] = (privilege.length + 1) * 2 + + with_lsa_policy(name) do |policy_handle, sid| + result = LsaAddAccountRights(policy_handle.read_pointer, sid, privilege_pointer, 1) + win32_error = LsaNtStatusToWinError(result) + if win32_error != 0 + Chef::ReservedNames::Win32::Error.raise!(nil, win32_error) + end + end + end + def self.adjust_token_privileges(token, privileges) token = token.handle if token.respond_to?(:handle) old_privileges_size = FFI::Buffer.new(:long).write_long(privileges.size_with_privileges) @@ -165,6 +181,29 @@ class Chef end end + def self.get_account_right(name) + privileges = [] + privilege_pointer = FFI::MemoryPointer.new(:pointer) + privilege_length = FFI::MemoryPointer.new(:ulong) + + with_lsa_policy(name) do |policy_handle, sid| + result = LsaEnumerateAccountRights(policy_handle.read_pointer, sid, privilege_pointer, privilege_length) + win32_error = LsaNtStatusToWinError(result) + return [] if win32_error == 2 # FILE_NOT_FOUND - No rights assigned + if win32_error != 0 + Chef::ReservedNames::Win32::Error.raise!(nil, win32_error) + end + + privilege_length.read_ulong.times do |i| + privilege = LSA_UNICODE_STRING.new(privilege_pointer.read_pointer + i * LSA_UNICODE_STRING.size) + privileges << privilege[:Buffer].read_wstring + end + LsaFreeMemory(privilege_pointer) + end + + privileges + end + def self.get_ace(acl, index) acl = acl.pointer if acl.respond_to?(:pointer) ace = FFI::Buffer.new :pointer @@ -548,6 +587,30 @@ class Chef end end + def self.with_lsa_policy(username) + sid = lookup_account_name(username)[1] + + access = 0 + access |= POLICY_CREATE_ACCOUNT + access |= POLICY_LOOKUP_NAMES + + policy_handle = FFI::MemoryPointer.new(:pointer) + result = LsaOpenPolicy(nil, LSA_OBJECT_ATTRIBUTES.new, access, policy_handle) + win32_error = LsaNtStatusToWinError(result) + if win32_error != 0 + Chef::ReservedNames::Win32::Error.raise!(nil, win32_error) + end + + begin + yield policy_handle, sid.pointer + ensure + win32_error = LsaNtStatusToWinError(LsaClose(policy_handle.read_pointer)) + if win32_error != 0 + Chef::ReservedNames::Win32::Error.raise!(nil, win32_error) + end + end + end + def self.with_privileges(*privilege_names) # Set privileges token = open_current_process_token(TOKEN_READ | TOKEN_ADJUST_PRIVILEGES) |