class Chef::ReservedNames::Win32::Security

Public Class Methods

access_check(security_descriptor, token, desired_access, generic_mapping) click to toggle source
# File lib/chef/win32/security.rb, line 38
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
add_access_allowed_ace(acl, sid, access_mask, revision = ACL_REVISION) click to toggle source
# File lib/chef/win32/security.rb, line 75
def self.add_access_allowed_ace(acl, sid, access_mask, revision = ACL_REVISION)
  acl = acl.pointer if acl.respond_to?(:pointer)
  sid = sid.pointer if sid.respond_to?(:pointer)
  unless AddAccessAllowedAce(acl, revision, access_mask, sid)
    Chef::ReservedNames::Win32::Error.raise!
  end
end
add_access_allowed_ace_ex(acl, sid, access_mask, flags = 0, revision = ACL_REVISION) click to toggle source
# File lib/chef/win32/security.rb, line 83
def self.add_access_allowed_ace_ex(acl, sid, access_mask, flags = 0, revision = ACL_REVISION)
  acl = acl.pointer if acl.respond_to?(:pointer)
  sid = sid.pointer if sid.respond_to?(:pointer)
  unless AddAccessAllowedAceEx(acl, revision, flags, access_mask, sid)
    Chef::ReservedNames::Win32::Error.raise!
  end
end
add_access_denied_ace(acl, sid, access_mask, revision = ACL_REVISION) click to toggle source
# File lib/chef/win32/security.rb, line 91
def self.add_access_denied_ace(acl, sid, access_mask, revision = ACL_REVISION)
  acl = acl.pointer if acl.respond_to?(:pointer)
  sid = sid.pointer if sid.respond_to?(:pointer)
  unless AddAccessDeniedAce(acl, revision, access_mask, sid)
    Chef::ReservedNames::Win32::Error.raise!
  end
end
add_access_denied_ace_ex(acl, sid, access_mask, flags = 0, revision = ACL_REVISION) click to toggle source
# File lib/chef/win32/security.rb, line 99
def self.add_access_denied_ace_ex(acl, sid, access_mask, flags = 0, revision = ACL_REVISION)
  acl = acl.pointer if acl.respond_to?(:pointer)
  sid = sid.pointer if sid.respond_to?(:pointer)
  unless AddAccessDeniedAceEx(acl, revision, flags, access_mask, sid)
    Chef::ReservedNames::Win32::Error.raise!
  end
end
add_account_right(name, privilege) click to toggle source
# File lib/chef/win32/security.rb, line 107
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)
    test_and_raise_lsa_nt_status(result)
  end
end
add_ace(acl, ace, insert_position = MAXDWORD, revision = ACL_REVISION) click to toggle source
# File lib/chef/win32/security.rb, line 66
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)
  ace_size = ACE_HEADER.new(ace)[:AceSize]
  unless AddAce(acl, revision, insert_position, ace, ace_size)
    Chef::ReservedNames::Win32::Error.raise!
  end
end
adjust_token_privileges(token, privileges) click to toggle source
# File lib/chef/win32/security.rb, line 133
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)
  old_privileges = TOKEN_PRIVILEGES.new(FFI::Buffer.new(old_privileges_size.read_long))
  unless AdjustTokenPrivileges(token.handle, false, privileges, privileges.size_with_privileges, old_privileges, old_privileges_size)
    Chef::ReservedNames::Win32::Error.raise!
  end

  old_privileges
end
convert_sid_to_string_sid(sid) click to toggle source
# File lib/chef/win32/security.rb, line 144
def self.convert_sid_to_string_sid(sid)
  sid = sid.pointer if sid.respond_to?(:pointer)
  result = FFI::MemoryPointer.new :pointer
  # TODO: use the W version
  unless ConvertSidToStringSidA(sid, result)
    Chef::ReservedNames::Win32::Error.raise!
  end

  result_string = result.read_pointer.read_string

  Chef::ReservedNames::Win32::Memory.local_free(result.read_pointer)

  result_string
end
convert_string_sid_to_sid(string_sid) click to toggle source
# File lib/chef/win32/security.rb, line 159
def self.convert_string_sid_to_sid(string_sid)
  result = FFI::MemoryPointer.new :pointer
  unless ConvertStringSidToSidW(string_sid.to_wstring, result)
    Chef::ReservedNames::Win32::Error.raise!
  end

  result_pointer = result.read_pointer
  sid = SID.new(result_pointer)

  # The result pointer must be freed with local_free
  ObjectSpace.define_finalizer(sid, Memory.local_free_finalizer(result_pointer))

  sid
end
delete_ace(acl, index) click to toggle source
# File lib/chef/win32/security.rb, line 174
def self.delete_ace(acl, index)
  acl = acl.pointer if acl.respond_to?(:pointer)
  unless DeleteAce(acl, index)
    Chef::ReservedNames::Win32::Error.raise!
  end
end
equal_sid(sid1, sid2) click to toggle source
# File lib/chef/win32/security.rb, line 181
def self.equal_sid(sid1, sid2)
  sid1 = sid1.pointer if sid1.respond_to?(:pointer)
  sid2 = sid2.pointer if sid2.respond_to?(:pointer)
  EqualSid(sid1, sid2)
end
free_sid(sid) click to toggle source
# File lib/chef/win32/security.rb, line 187
def self.free_sid(sid)
  sid = sid.pointer if sid.respond_to?(:pointer)
  unless FreeSid(sid).null?
    Chef::ReservedNames::Win32::Error.raise!
  end
end
get_account_right(name) click to toggle source
# File lib/chef/win32/security.rb, line 194
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

    test_and_raise_lsa_nt_status(result)

    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
    result = LsaFreeMemory(privilege_pointer.read_pointer)
    test_and_raise_lsa_nt_status(result)
  end

  privileges
end
get_account_with_user_rights(privilege) click to toggle source
# File lib/chef/win32/security.rb, line 217
def self.get_account_with_user_rights(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

  buffer = FFI::MemoryPointer.new(:pointer)
  count = FFI::MemoryPointer.new(:ulong)

  accounts = []
  with_lsa_policy(nil) do |policy_handle, sid|
    result = LsaEnumerateAccountsWithUserRight(policy_handle.read_pointer, privilege_pointer, buffer, count)
    if result == 0
      win32_error = LsaNtStatusToWinError(result)
      return [] if win32_error == 1313 # NO_SUCH_PRIVILEGE - https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--1300-1699-

      test_and_raise_lsa_nt_status(result)

      count.read_ulong.times do |i|
        sid = LSA_ENUMERATION_INFORMATION.new(buffer.read_pointer + i * LSA_ENUMERATION_INFORMATION.size)
        sid_name = lookup_account_sid(sid[:Sid])
        domain, name, use = sid_name
        account_name = (!domain.nil? && domain.length > 0) ? "#{domain}\\#{name}" : name
        accounts << account_name
      end
    end

    result = LsaFreeMemory(buffer.read_pointer)
    test_and_raise_lsa_nt_status(result)
  end

  accounts
end
get_ace(acl, index) click to toggle source
# File lib/chef/win32/security.rb, line 252
def self.get_ace(acl, index)
  acl = acl.pointer if acl.respond_to?(:pointer)
  ace = FFI::Buffer.new :pointer
  unless GetAce(acl, index, ace)
    Chef::ReservedNames::Win32::Error.raise!
  end
  ACE.new(ace.read_pointer, acl)
end
get_file_security(path, info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION) click to toggle source
# File lib/chef/win32/security.rb, line 266
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
get_length_sid(sid) click to toggle source
# File lib/chef/win32/security.rb, line 261
def self.get_length_sid(sid)
  sid = sid.pointer if sid.respond_to?(:pointer)
  GetLengthSid(sid)
end
get_named_security_info(path, type = :SE_FILE_OBJECT, info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION) click to toggle source
# File lib/chef/win32/security.rb, line 283
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)
  if hr != ERROR_SUCCESS
    Chef::ReservedNames::Win32::Error.raise!("get_named_security_info(#{path}, #{type}, #{info})", hr)
  end

  result_pointer = security_descriptor.read_pointer
  result = SecurityDescriptor.new(result_pointer)

  # This memory has to be freed with LocalFree.
  ObjectSpace.define_finalizer(result, Memory.local_free_finalizer(result_pointer))

  result
end
get_security_descriptor_control(security_descriptor) click to toggle source
# File lib/chef/win32/security.rb, line 299
def self.get_security_descriptor_control(security_descriptor)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  result = FFI::Buffer.new :ushort
  version = FFI::Buffer.new :uint32
  unless GetSecurityDescriptorControl(security_descriptor, result, version)
    Chef::ReservedNames::Win32::Error.raise!
  end
  [ result.read_ushort, version.read_uint32 ]
end
get_security_descriptor_dacl(security_descriptor) click to toggle source
# File lib/chef/win32/security.rb, line 309
def self.get_security_descriptor_dacl(security_descriptor)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  present = FFI::Buffer.new :bool
  defaulted = FFI::Buffer.new :bool
  acl = FFI::Buffer.new :pointer
  unless GetSecurityDescriptorDacl(security_descriptor, present, acl, defaulted)
    Chef::ReservedNames::Win32::Error.raise!
  end
  acl = acl.read_pointer
  [ present.read_char != 0, acl.null? ? nil : ACL.new(acl, security_descriptor), defaulted.read_char != 0 ]
end
get_security_descriptor_group(security_descriptor) click to toggle source
# File lib/chef/win32/security.rb, line 321
def self.get_security_descriptor_group(security_descriptor)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  result = FFI::Buffer.new :pointer
  defaulted = FFI::Buffer.new :long
  unless GetSecurityDescriptorGroup(security_descriptor, result, defaulted)
    Chef::ReservedNames::Win32::Error.raise!
  end

  sid = SID.new(result.read_pointer, security_descriptor)
  defaulted = defaulted.read_char != 0
  [ sid, defaulted ]
end
get_security_descriptor_owner(security_descriptor) click to toggle source
# File lib/chef/win32/security.rb, line 334
def self.get_security_descriptor_owner(security_descriptor)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  result = FFI::Buffer.new :pointer
  defaulted = FFI::Buffer.new :long
  unless GetSecurityDescriptorOwner(security_descriptor, result, defaulted)
    Chef::ReservedNames::Win32::Error.raise!
  end

  sid = SID.new(result.read_pointer, security_descriptor)
  defaulted = defaulted.read_char != 0
  [ sid, defaulted ]
end
get_security_descriptor_sacl(security_descriptor) click to toggle source
# File lib/chef/win32/security.rb, line 347
def self.get_security_descriptor_sacl(security_descriptor)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  present = FFI::Buffer.new :bool
  defaulted = FFI::Buffer.new :bool
  acl = FFI::Buffer.new :pointer
  unless GetSecurityDescriptorSacl(security_descriptor, present, acl, defaulted)
    Chef::ReservedNames::Win32::Error.raise!
  end
  acl = acl.read_pointer
  [ present.read_char != 0, acl.null? ? nil : ACL.new(acl, security_descriptor), defaulted.read_char != 0 ]
end
get_token_information_elevation_type(token) click to toggle source
# File lib/chef/win32/security.rb, line 391
def self.get_token_information_elevation_type(token)
  token_result_size = FFI::MemoryPointer.new(:ulong)
  if GetTokenInformation(token.handle.handle, :TokenElevationType, nil, 0, token_result_size)
    raise "Expected ERROR_INSUFFICIENT_BUFFER from GetTokenInformation, and got no error!"
  elsif FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER
    Chef::ReservedNames::Win32::Error.raise!
  end

  info_ptr = FFI::MemoryPointer.new(:pointer)
  token_info_pointer = TOKEN_ELEVATION_TYPE.new info_ptr
  token_info_length = 4
  unless GetTokenInformation(token.handle.handle, :TokenElevationType, token_info_pointer, token_info_length, token_result_size)
    Chef::ReservedNames::Win32::Error.raise!
  end
  token_info_pointer[:ElevationType]
end
get_token_information_owner(token) click to toggle source
# File lib/chef/win32/security.rb, line 359
def self.get_token_information_owner(token)
  owner_result_size = FFI::MemoryPointer.new(:ulong)
  if GetTokenInformation(token.handle.handle, :TokenOwner, nil, 0, owner_result_size)
    raise "Expected ERROR_INSUFFICIENT_BUFFER from GetTokenInformation, and got no error!"
  elsif FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER
    Chef::ReservedNames::Win32::Error.raise!
  end

  owner_result_storage = FFI::MemoryPointer.new owner_result_size.read_ulong
  unless GetTokenInformation(token.handle.handle, :TokenOwner, owner_result_storage, owner_result_size.read_ulong, owner_result_size)
    Chef::ReservedNames::Win32::Error.raise!
  end
  owner_result = TOKEN_OWNER.new owner_result_storage
  SID.new(owner_result[:Owner], owner_result_storage)
end
get_token_information_primary_group(token) click to toggle source
# File lib/chef/win32/security.rb, line 375
def self.get_token_information_primary_group(token)
  group_result_size = FFI::MemoryPointer.new(:ulong)
  if GetTokenInformation(token.handle.handle, :TokenPrimaryGroup, nil, 0, group_result_size)
    raise "Expected ERROR_INSUFFICIENT_BUFFER from GetTokenInformation, and got no error!"
  elsif FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER
    Chef::ReservedNames::Win32::Error.raise!
  end

  group_result_storage = FFI::MemoryPointer.new group_result_size.read_ulong
  unless GetTokenInformation(token.handle.handle, :TokenPrimaryGroup, group_result_storage, group_result_size.read_ulong, group_result_size)
    Chef::ReservedNames::Win32::Error.raise!
  end
  group_result = TOKEN_PRIMARY_GROUP.new group_result_storage
  SID.new(group_result[:PrimaryGroup], group_result_storage)
end
has_admin_privileges?() click to toggle source

Checks if the caller has the admin privileges in their security token

# File lib/chef/win32/security.rb, line 691
def self.has_admin_privileges?
  # a regular user doesn't have privileges to call Chef::ReservedNames::Win32::Security.OpenProcessToken
  # hence we return false if the open_current_process_token fails with `Access is denied.` error message.
  begin
    process_token = open_current_process_token(TOKEN_READ)
  rescue Exception => run_error
    return false if /Access is denied/.match?(run_error.message)

    Chef::ReservedNames::Win32::Error.raise!
  end

  # display token elevation details
  token_elevation_type = get_token_information_elevation_type(process_token)
  Chef::Log.trace("Token Elevation Type: #{token_elevation_type}")

  elevation_result = FFI::Buffer.new(:ulong)
  elevation_result_size = FFI::MemoryPointer.new(:uint32)
  success = GetTokenInformation(process_token.handle.handle, :TokenElevation, elevation_result, 4, elevation_result_size)

  # Assume process is not elevated if the call fails.
  # Process is elevated if the result is different than 0.
  success && (elevation_result.read_ulong != 0)
end
initialize_acl(acl_size) click to toggle source
# File lib/chef/win32/security.rb, line 408
def self.initialize_acl(acl_size)
  acl = FFI::MemoryPointer.new acl_size
  unless InitializeAcl(acl, acl_size, ACL_REVISION)
    Chef::ReservedNames::Win32::Error.raise!
  end
  ACL.new(acl)
end
initialize_security_descriptor(revision = SECURITY_DESCRIPTOR_REVISION) click to toggle source
# File lib/chef/win32/security.rb, line 416
def self.initialize_security_descriptor(revision = SECURITY_DESCRIPTOR_REVISION)
  security_descriptor = FFI::MemoryPointer.new SECURITY_DESCRIPTOR_MIN_LENGTH
  unless InitializeSecurityDescriptor(security_descriptor, revision)
    Chef::ReservedNames::Win32::Error.raise!
  end
  SecurityDescriptor.new(security_descriptor)
end
is_valid_acl(acl) click to toggle source
# File lib/chef/win32/security.rb, line 424
def self.is_valid_acl(acl)
  acl = acl.pointer if acl.respond_to?(:pointer)
  IsValidAcl(acl) != 0
end
is_valid_security_descriptor(security_descriptor) click to toggle source
# File lib/chef/win32/security.rb, line 429
def self.is_valid_security_descriptor(security_descriptor)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  IsValidSecurityDescriptor(security_descriptor) != 0
end
is_valid_sid(sid) click to toggle source
# File lib/chef/win32/security.rb, line 434
def self.is_valid_sid(sid)
  sid = sid.pointer if sid.respond_to?(:pointer)
  IsValidSid(sid) != 0
end
logon_user(username, domain, password, logon_type, logon_provider) click to toggle source
# File lib/chef/win32/security.rb, line 715
def self.logon_user(username, domain, password, logon_type, logon_provider)
  username = wstring(username)
  domain = wstring(domain)
  password = wstring(password)

  token = FFI::Buffer.new(:pointer)
  unless LogonUserW(username, domain, password, logon_type, logon_provider, token)
    Chef::ReservedNames::Win32::Error.raise!
  end

  # originally this was .read_pointer, but that is interpreted as a non-primitive
  # class (FFI::Pointer) and causes an ArgumentError (Invalid Memory Object) when
  # compared to GetCurrentProcess(), which returns a HANDLE (void *). Since a
  # HANDLE is not a pointer to allocated memory that Ruby C extensions can understand,
  # the Invalid Memory Object error is raised.
  Token.new(Handle.new(token.read_ulong))
end
lookup_account_name(name, system_name = nil) click to toggle source
# File lib/chef/win32/security.rb, line 439
def self.lookup_account_name(name, system_name = nil)
  # Figure out how big the buffers need to be
  sid_size = FFI::Buffer.new(:long).write_long(0)
  referenced_domain_name_size = FFI::Buffer.new(:long).write_long(0)
  system_name = system_name.to_wstring if system_name
  if LookupAccountNameW(system_name, name.to_wstring, nil, sid_size, nil, referenced_domain_name_size, nil)
    raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupAccountName, and got no error!"
  elsif !([NO_ERROR, ERROR_INSUFFICIENT_BUFFER].include?(FFI::LastError.error))
    Chef::ReservedNames::Win32::Error.raise!
  end

  sid = FFI::MemoryPointer.new :char, sid_size.read_long
  referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long * 2)
  use = FFI::Buffer.new(:long).write_long(0)
  unless LookupAccountNameW(system_name, name.to_wstring, sid, sid_size, referenced_domain_name, referenced_domain_name_size, use)
    Chef::ReservedNames::Win32::Error.raise!
  end

  [ referenced_domain_name.read_wstring(referenced_domain_name_size.read_long), SID.new(sid), use.read_long ]
end
lookup_account_sid(sid, system_name = nil) click to toggle source
# File lib/chef/win32/security.rb, line 460
def self.lookup_account_sid(sid, system_name = nil)
  sid = sid.pointer if sid.respond_to?(:pointer)
  # Figure out how big the buffer needs to be
  name_size = FFI::Buffer.new(:long).write_long(0)
  referenced_domain_name_size = FFI::Buffer.new(:long).write_long(0)
  system_name = system_name.to_wstring if system_name
  if LookupAccountSidW(system_name, sid, nil, name_size, nil, referenced_domain_name_size, nil)
    raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupAccountSid, and got no error!"
  elsif FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER
    Chef::ReservedNames::Win32::Error.raise!
  end

  name = FFI::MemoryPointer.new :char, (name_size.read_long * 2)
  referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long * 2)
  use = FFI::Buffer.new(:long).write_long(0)
  unless LookupAccountSidW(system_name, sid, name, name_size, referenced_domain_name, referenced_domain_name_size, use)
    Chef::ReservedNames::Win32::Error.raise!
  end

  [ referenced_domain_name.read_wstring(referenced_domain_name_size.read_long), name.read_wstring(name_size.read_long), use.read_long ]
end
lookup_privilege_display_name(system_name, name) click to toggle source
# File lib/chef/win32/security.rb, line 499
def self.lookup_privilege_display_name(system_name, name)
  system_name = system_name.to_wstring if system_name
  display_name_size = FFI::Buffer.new(:long).write_long(0)
  language_id = FFI::Buffer.new(:long)
  if LookupPrivilegeDisplayNameW(system_name, name.to_wstring, nil, display_name_size, language_id)
    raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupPrivilegeDisplayName, and got no error!"
  elsif FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER
    Chef::ReservedNames::Win32::Error.raise!
  end

  display_name = FFI::MemoryPointer.new :char, (display_name_size.read_long * 2)
  unless LookupPrivilegeDisplayNameW(system_name, name.to_wstring, display_name, display_name_size, language_id)
    Chef::ReservedNames::Win32::Error.raise!
  end

  [ display_name.read_wstring(display_name_size.read_long), language_id.read_long ]
end
lookup_privilege_name(system_name, luid) click to toggle source
# File lib/chef/win32/security.rb, line 482
def self.lookup_privilege_name(system_name, luid)
  system_name = system_name.to_wstring if system_name
  name_size = FFI::Buffer.new(:long).write_long(0)
  if LookupPrivilegeNameW(system_name, luid, nil, name_size)
    raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupPrivilegeName, and got no error!"
  elsif FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER
    Chef::ReservedNames::Win32::Error.raise!
  end

  name = FFI::MemoryPointer.new :char, (name_size.read_long * 2)
  unless LookupPrivilegeNameW(system_name, luid, name, name_size)
    Chef::ReservedNames::Win32::Error.raise!
  end

  name.read_wstring(name_size.read_long)
end
lookup_privilege_value(system_name, name) click to toggle source
# File lib/chef/win32/security.rb, line 517
def self.lookup_privilege_value(system_name, name)
  luid = FFI::Buffer.new(:uint64).write_uint64(0)
  system_name = system_name.to_wstring if system_name
  unless LookupPrivilegeValueW(system_name, name.to_wstring, luid)
    Win32::Error.raise!
  end
  luid.read_uint64
end
make_absolute_sd(security_descriptor) click to toggle source
# File lib/chef/win32/security.rb, line 526
def self.make_absolute_sd(security_descriptor)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)

  # Figure out buffer sizes
  absolute_sd_size = FFI::Buffer.new(:long).write_long(0)
  dacl_size = FFI::Buffer.new(:long).write_long(0)
  sacl_size = FFI::Buffer.new(:long).write_long(0)
  owner_size = FFI::Buffer.new(:long).write_long(0)
  group_size = FFI::Buffer.new(:long).write_long(0)
  if MakeAbsoluteSD(security_descriptor, nil, absolute_sd_size, nil, dacl_size, nil, sacl_size, nil, owner_size, nil, group_size)
    raise "Expected ERROR_INSUFFICIENT_BUFFER from MakeAbsoluteSD, and got no error!"
  elsif FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER
    Chef::ReservedNames::Win32::Error.raise!
  end

  absolute_sd = FFI::MemoryPointer.new absolute_sd_size.read_long
  owner = FFI::MemoryPointer.new owner_size.read_long
  group = FFI::MemoryPointer.new group_size.read_long
  dacl = FFI::MemoryPointer.new dacl_size.read_long
  sacl = FFI::MemoryPointer.new sacl_size.read_long
  unless MakeAbsoluteSD(security_descriptor, absolute_sd, absolute_sd_size, dacl, dacl_size, sacl, sacl_size, owner, owner_size, group, group_size)
    Chef::ReservedNames::Win32::Error.raise!
  end

  [ SecurityDescriptor.new(absolute_sd), SID.new(owner), SID.new(group), ACL.new(dacl), ACL.new(sacl) ]
end
open_current_process_token(desired_access = TOKEN_READ) click to toggle source
# File lib/chef/win32/security.rb, line 553
def self.open_current_process_token(desired_access = TOKEN_READ)
  open_process_token(Chef::ReservedNames::Win32::Process.get_current_process, desired_access)
end
open_process_token(process, desired_access) click to toggle source
# File lib/chef/win32/security.rb, line 557
def self.open_process_token(process, desired_access)
  process = process.handle if process.respond_to?(:handle)
  process = process.handle if process.respond_to?(:handle)
  token = FFI::Buffer.new(:ulong)
  unless OpenProcessToken(process, desired_access, token)
    Chef::ReservedNames::Win32::Error.raise!
  end
  Token.new(Handle.new(token.read_ulong))
end
query_security_access_mask(security_information) click to toggle source
# File lib/chef/win32/security.rb, line 567
def self.query_security_access_mask(security_information)
  result = FFI::Buffer.new(:long)
  QuerySecurityAccessMask(security_information, result)
  result.read_long
end
remove_account_right(name, privilege) click to toggle source
# File lib/chef/win32/security.rb, line 120
def self.remove_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 = LsaRemoveAccountRights(policy_handle.read_pointer, sid, false, privilege_pointer, 1)
    test_and_raise_lsa_nt_status(result)
  end
end
set_file_security(path, security_information, security_descriptor) click to toggle source
# File lib/chef/win32/security.rb, line 573
def self.set_file_security(path, security_information, security_descriptor)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  unless SetFileSecurityW(path.to_wstring, security_information, security_descriptor)
    Chef::ReservedNames::Win32::Error.raise!
  end
end
set_named_security_info(path, type, args) click to toggle source
# File lib/chef/win32/security.rb, line 580
def self.set_named_security_info(path, type, args)
  owner = args[:owner]
  group = args[:group]
  dacl = args[:dacl]
  sacl = args[:sacl]
  owner = owner.pointer if owner && owner.respond_to?(:pointer)
  group = group.pointer if group && group.respond_to?(:pointer)
  dacl = dacl.pointer if dacl && dacl.respond_to?(:pointer)
  sacl = sacl.pointer if sacl && sacl.respond_to?(:pointer)

  # Determine the security_information flags
  security_information = 0
  security_information |= OWNER_SECURITY_INFORMATION if args.key?(:owner)
  security_information |= GROUP_SECURITY_INFORMATION if args.key?(:group)
  security_information |= DACL_SECURITY_INFORMATION if args.key?(:dacl)
  security_information |= SACL_SECURITY_INFORMATION if args.key?(:sacl)
  if args.key?(:dacl_inherits)
    security_information |= (args[:dacl_inherits] ? UNPROTECTED_DACL_SECURITY_INFORMATION : PROTECTED_DACL_SECURITY_INFORMATION)
  end
  if args.key?(:sacl_inherits)
    security_information |= (args[:sacl_inherits] ? UNPROTECTED_SACL_SECURITY_INFORMATION : PROTECTED_SACL_SECURITY_INFORMATION)
  end

  hr = SetNamedSecurityInfoW(path.to_wstring, type, security_information, owner, group, dacl, sacl)
  if hr != ERROR_SUCCESS
    Chef::ReservedNames::Win32::Error.raise! nil, hr
  end
end
set_security_access_mask(security_information) click to toggle source
# File lib/chef/win32/security.rb, line 609
def self.set_security_access_mask(security_information)
  result = FFI::Buffer.new(:long)
  SetSecurityAccessMask(security_information, result)
  result.read_long
end
set_security_descriptor_group(security_descriptor, sid, defaulted = false) click to toggle source
# File lib/chef/win32/security.rb, line 625
def self.set_security_descriptor_group(security_descriptor, sid, defaulted = false)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  sid = sid.pointer if sid.respond_to?(:pointer)

  unless SetSecurityDescriptorGroup(security_descriptor, sid, defaulted)
    Chef::ReservedNames::Win32::Error.raise!
  end
end
set_security_descriptor_owner(security_descriptor, sid, defaulted = false) click to toggle source
# File lib/chef/win32/security.rb, line 634
def self.set_security_descriptor_owner(security_descriptor, sid, defaulted = false)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  sid = sid.pointer if sid.respond_to?(:pointer)

  unless SetSecurityDescriptorOwner(security_descriptor, sid, defaulted)
    Chef::ReservedNames::Win32::Error.raise!
  end
end
set_security_descriptor_sacl(security_descriptor, acl, defaulted = false, present = nil) click to toggle source
# File lib/chef/win32/security.rb, line 643
def self.set_security_descriptor_sacl(security_descriptor, acl, defaulted = false, present = nil)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  acl = acl.pointer if acl.respond_to?(:pointer)
  present = !security_descriptor.null? if present.nil?

  unless SetSecurityDescriptorSacl(security_descriptor, present, acl, defaulted)
    Chef::ReservedNames::Win32::Error.raise!
  end
end
test_and_raise_lsa_nt_status(result) click to toggle source
# File lib/chef/win32/security.rb, line 733
def self.test_and_raise_lsa_nt_status(result)
  win32_error = LsaNtStatusToWinError(result)
  if win32_error != 0
    Chef::ReservedNames::Win32::Error.raise!(nil, win32_error)
  end
end
with_lsa_policy(username) { |policy_handle, sid_pointer| ... } click to toggle source
# File lib/chef/win32/security.rb, line 653
def self.with_lsa_policy(username)
  sid = lookup_account_name(username)[1] if username

  access = 0
  access |= POLICY_CREATE_ACCOUNT
  access |= POLICY_LOOKUP_NAMES
  access |= POLICY_VIEW_LOCAL_INFORMATION if username.nil?

  policy_handle = FFI::MemoryPointer.new(:pointer)
  result = LsaOpenPolicy(nil, LSA_OBJECT_ATTRIBUTES.new, access, policy_handle)
  test_and_raise_lsa_nt_status(result)

  sid_pointer = username.nil? ? nil : sid.pointer

  begin
    yield policy_handle, sid_pointer
  ensure
    result = LsaClose(policy_handle.read_pointer)
    test_and_raise_lsa_nt_status(result)
  end
end
with_privileges(*privilege_names) { || ... } click to toggle source
# File lib/chef/win32/security.rb, line 675
def self.with_privileges(*privilege_names)
  # Set privileges
  token = open_current_process_token(TOKEN_READ | TOKEN_ADJUST_PRIVILEGES)
  old_privileges = token.enable_privileges(*privilege_names)

  # Let the caller do their privileged stuff
  begin
    yield
  ensure
    # Set privileges back to what they were before
    token.adjust_privileges(old_privileges)
  end
end

Public Instance Methods

set_security_descriptor_dacl(security_descriptor, acl, defaulted = false, present = nil) click to toggle source
# File lib/chef/win32/security.rb, line 615
def set_security_descriptor_dacl(security_descriptor, acl, defaulted = false, present = nil)
  security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
  acl = acl.pointer if acl.respond_to?(:pointer)
  present = !security_descriptor.null? if present.nil?

  unless SetSecurityDescriptorDacl(security_descriptor, present, acl, defaulted)
    Chef::ReservedNames::Win32::Error.raise!
  end
end